[osm2pgsql] 02/18: Imported Upstream version 0.90.0~rc1

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Sat Feb 27 15:33:45 UTC 2016


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository osm2pgsql.

commit e3642ccd10108dfb11941087c59379606a1fa182
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sat Feb 27 14:41:47 2016 +0100

    Imported Upstream version 0.90.0~rc1
---
 .gitignore                                         |   70 +-
 .travis.yml                                        |   82 +-
 CMakeLists.txt                                     |  266 +++
 CONTRIBUTING.md                                    |   22 +-
 Makefile.am                                        |  188 --
 NEWS                                               |   10 -
 README.md                                          |   88 +-
 UTF8sanitizer.cpp                                  |  160 --
 appveyor.yml                                       |   69 +
 autogen.sh                                         |    2 -
 cmake/FindLua.cmake                                |  171 ++
 cmake/FindOsmium.cmake                             |  317 +++
 cmake/config.h.in                                  |   35 +
 configure.ac                                       |  171 --
 contrib/libosmium/LICENSE.txt                      |   23 +
 contrib/libosmium/README.contrib                   |    2 +
 contrib/libosmium/README.md                        |  108 +
 contrib/libosmium/osmium/area/assembler.hpp        |  787 +++++++
 .../osmium/area/detail/node_ref_segment.hpp        |  262 +++
 .../libosmium/osmium/area/detail/proto_ring.hpp    |  277 +++
 .../libosmium/osmium/area/detail/segment_list.hpp  |  218 ++
 .../osmium/area/multipolygon_collector.hpp         |  223 ++
 contrib/libosmium/osmium/area/problem_reporter.hpp |  149 ++
 .../osmium/area/problem_reporter_exception.hpp     |   96 +
 .../libosmium/osmium/area/problem_reporter_ogr.hpp |  139 ++
 .../osmium/area/problem_reporter_stream.hpp        |   96 +
 contrib/libosmium/osmium/builder/builder.hpp       |  237 ++
 .../libosmium/osmium/builder/builder_helper.hpp    |  103 +
 .../osmium/builder/osm_object_builder.hpp          |  370 +++
 contrib/libosmium/osmium/diff_handler.hpp          |   67 +
 contrib/libosmium/osmium/diff_iterator.hpp         |  129 ++
 contrib/libosmium/osmium/diff_visitor.hpp          |  104 +
 contrib/libosmium/osmium/dynamic_handler.hpp       |  190 ++
 .../libosmium/osmium/experimental/flex_reader.hpp  |  137 ++
 contrib/libosmium/osmium/fwd.hpp                   |   70 +
 contrib/libosmium/osmium/geom/coordinates.hpp      |   96 +
 contrib/libosmium/osmium/geom/factory.hpp          |  419 ++++
 contrib/libosmium/osmium/geom/geojson.hpp          |  160 ++
 contrib/libosmium/osmium/geom/geos.hpp             |  240 ++
 contrib/libosmium/osmium/geom/haversine.hpp        |   94 +
 .../libosmium/osmium/geom/mercator_projection.hpp  |  110 +
 contrib/libosmium/osmium/geom/ogr.hpp              |  178 ++
 contrib/libosmium/osmium/geom/projection.hpp       |  167 ++
 contrib/libosmium/osmium/geom/rapid_geojson.hpp    |  190 ++
 contrib/libosmium/osmium/geom/relations.hpp        |   57 +
 contrib/libosmium/osmium/geom/tile.hpp             |  101 +
 contrib/libosmium/osmium/geom/util.hpp             |   75 +
 contrib/libosmium/osmium/geom/wkb.hpp              |  273 +++
 contrib/libosmium/osmium/geom/wkt.hpp              |  156 ++
 contrib/libosmium/osmium/handler.hpp               |   94 +
 contrib/libosmium/osmium/handler/chain.hpp         |  128 ++
 contrib/libosmium/osmium/handler/disk_store.hpp    |  111 +
 contrib/libosmium/osmium/handler/dump.hpp          |  294 +++
 .../osmium/handler/node_locations_for_ways.hpp     |  180 ++
 .../libosmium/osmium/handler/object_relations.hpp  |  106 +
 contrib/libosmium/osmium/index/bool_vector.hpp     |   85 +
 .../osmium/index/detail/create_map_with_fd.hpp     |   71 +
 .../osmium/index/detail/mmap_vector_anon.hpp       |   67 +
 .../osmium/index/detail/mmap_vector_base.hpp       |  180 ++
 .../osmium/index/detail/mmap_vector_file.hpp       |   74 +
 contrib/libosmium/osmium/index/detail/tmpfile.hpp  |   62 +
 .../libosmium/osmium/index/detail/vector_map.hpp   |  246 ++
 .../osmium/index/detail/vector_multimap.hpp        |  186 ++
 contrib/libosmium/osmium/index/index.hpp           |  100 +
 contrib/libosmium/osmium/index/map.hpp             |  275 +++
 contrib/libosmium/osmium/index/map/all.hpp         |   46 +
 .../osmium/index/map/dense_file_array.hpp          |   67 +
 .../libosmium/osmium/index/map/dense_mem_array.hpp |   57 +
 .../osmium/index/map/dense_mmap_array.hpp          |   60 +
 contrib/libosmium/osmium/index/map/dummy.hpp       |   88 +
 .../osmium/index/map/sparse_file_array.hpp         |   67 +
 .../osmium/index/map/sparse_mem_array.hpp          |   60 +
 .../libosmium/osmium/index/map/sparse_mem_map.hpp  |  116 +
 .../osmium/index/map/sparse_mem_table.hpp          |  147 ++
 .../osmium/index/map/sparse_mmap_array.hpp         |   60 +
 contrib/libosmium/osmium/index/multimap.hpp        |  127 ++
 contrib/libosmium/osmium/index/multimap/all.hpp    |   41 +
 contrib/libosmium/osmium/index/multimap/hybrid.hpp |  204 ++
 .../osmium/index/multimap/sparse_file_array.hpp    |   54 +
 .../osmium/index/multimap/sparse_mem_array.hpp     |   58 +
 .../osmium/index/multimap/sparse_mem_multimap.hpp  |  151 ++
 .../osmium/index/multimap/sparse_mmap_array.hpp    |   58 +
 .../libosmium/osmium/index/node_locations_map.hpp  |   70 +
 contrib/libosmium/osmium/io/any_compression.hpp    |   48 +
 contrib/libosmium/osmium/io/any_input.hpp          |   52 +
 contrib/libosmium/osmium/io/any_output.hpp         |   53 +
 contrib/libosmium/osmium/io/bzip2_compression.hpp  |  321 +++
 contrib/libosmium/osmium/io/compression.hpp        |  321 +++
 contrib/libosmium/osmium/io/debug_output.hpp       |   39 +
 .../osmium/io/detail/debug_output_format.hpp       |  485 ++++
 .../libosmium/osmium/io/detail/input_format.hpp    |  211 ++
 .../osmium/io/detail/o5m_input_format.hpp          |  633 ++++++
 .../osmium/io/detail/opl_output_format.hpp         |  261 +++
 .../libosmium/osmium/io/detail/output_format.hpp   |  184 ++
 contrib/libosmium/osmium/io/detail/pbf.hpp         |   89 +
 contrib/libosmium/osmium/io/detail/pbf_decoder.hpp |  777 +++++++
 .../osmium/io/detail/pbf_input_format.hpp          |  242 ++
 .../osmium/io/detail/pbf_output_format.hpp         |  643 ++++++
 .../libosmium/osmium/io/detail/protobuf_tags.hpp   |  170 ++
 contrib/libosmium/osmium/io/detail/queue_util.hpp  |  157 ++
 contrib/libosmium/osmium/io/detail/read_thread.hpp |  133 ++
 contrib/libosmium/osmium/io/detail/read_write.hpp  |  180 ++
 .../libosmium/osmium/io/detail/string_table.hpp    |  265 +++
 contrib/libosmium/osmium/io/detail/string_util.hpp |  206 ++
 .../libosmium/osmium/io/detail/write_thread.hpp    |  107 +
 .../osmium/io/detail/xml_input_format.hpp          |  679 ++++++
 .../osmium/io/detail/xml_output_format.hpp         |  473 ++++
 contrib/libosmium/osmium/io/detail/zlib.hpp        |  115 +
 contrib/libosmium/osmium/io/error.hpp              |   70 +
 contrib/libosmium/osmium/io/file.hpp               |  328 +++
 contrib/libosmium/osmium/io/file_compression.hpp   |   72 +
 contrib/libosmium/osmium/io/file_format.hpp        |   84 +
 contrib/libosmium/osmium/io/gzip_compression.hpp   |  277 +++
 contrib/libosmium/osmium/io/header.hpp             |  122 +
 contrib/libosmium/osmium/io/input_iterator.hpp     |  178 ++
 contrib/libosmium/osmium/io/o5m_input.hpp          |   45 +
 contrib/libosmium/osmium/io/opl_output.hpp         |   39 +
 contrib/libosmium/osmium/io/output_iterator.hpp    |  133 ++
 contrib/libosmium/osmium/io/overwrite.hpp          |   39 +
 contrib/libosmium/osmium/io/pbf_input.hpp          |   48 +
 contrib/libosmium/osmium/io/pbf_output.hpp         |   48 +
 contrib/libosmium/osmium/io/reader.hpp             |  380 ++++
 contrib/libosmium/osmium/io/reader_iterator.hpp    |   51 +
 contrib/libosmium/osmium/io/writer.hpp             |  344 +++
 contrib/libosmium/osmium/io/writer_options.hpp     |   60 +
 contrib/libosmium/osmium/io/xml_input.hpp          |   48 +
 contrib/libosmium/osmium/io/xml_output.hpp         |   47 +
 contrib/libosmium/osmium/memory/buffer.hpp         |  617 +++++
 contrib/libosmium/osmium/memory/collection.hpp     |  153 ++
 contrib/libosmium/osmium/memory/item.hpp           |  177 ++
 contrib/libosmium/osmium/memory/item_iterator.hpp  |  234 ++
 .../libosmium/osmium/object_pointer_collection.hpp |  112 +
 contrib/libosmium/osmium/osm.hpp                   |   48 +
 contrib/libosmium/osmium/osm/area.hpp              |  215 ++
 contrib/libosmium/osmium/osm/box.hpp               |  250 +++
 contrib/libosmium/osmium/osm/changeset.hpp         |  458 ++++
 contrib/libosmium/osmium/osm/crc.hpp               |  242 ++
 contrib/libosmium/osmium/osm/diff_object.hpp       |  180 ++
 contrib/libosmium/osmium/osm/entity.hpp            |   80 +
 contrib/libosmium/osmium/osm/entity_bits.hpp       |  105 +
 contrib/libosmium/osmium/osm/item_type.hpp         |  200 ++
 contrib/libosmium/osmium/osm/location.hpp          |  285 +++
 contrib/libosmium/osmium/osm/node.hpp              |   76 +
 contrib/libosmium/osmium/osm/node_ref.hpp          |  173 ++
 contrib/libosmium/osmium/osm/node_ref_list.hpp     |  184 ++
 contrib/libosmium/osmium/osm/object.hpp            |  438 ++++
 .../libosmium/osmium/osm/object_comparisons.hpp    |  110 +
 contrib/libosmium/osmium/osm/relation.hpp          |  194 ++
 contrib/libosmium/osmium/osm/segment.hpp           |  105 +
 contrib/libosmium/osmium/osm/tag.hpp               |  140 ++
 contrib/libosmium/osmium/osm/timestamp.hpp         |  193 ++
 contrib/libosmium/osmium/osm/types.hpp             |   66 +
 contrib/libosmium/osmium/osm/types_from_string.hpp |  122 +
 .../libosmium/osmium/osm/undirected_segment.hpp    |  100 +
 contrib/libosmium/osmium/osm/way.hpp               |  117 +
 contrib/libosmium/osmium/relations/collector.hpp   |  544 +++++
 .../osmium/relations/detail/member_meta.hpp        |  158 ++
 .../osmium/relations/detail/relation_meta.hpp      |  136 ++
 contrib/libosmium/osmium/tags/filter.hpp           |  162 ++
 contrib/libosmium/osmium/tags/regex_filter.hpp     |   58 +
 contrib/libosmium/osmium/tags/taglist.hpp          |   67 +
 .../libosmium/osmium/thread/function_wrapper.hpp   |  123 +
 contrib/libosmium/osmium/thread/pool.hpp           |  190 ++
 contrib/libosmium/osmium/thread/queue.hpp          |  192 ++
 contrib/libosmium/osmium/thread/sorted_queue.hpp   |  159 ++
 contrib/libosmium/osmium/thread/util.hpp           |  116 +
 contrib/libosmium/osmium/util/cast.hpp             |  103 +
 contrib/libosmium/osmium/util/compatibility.hpp    |   56 +
 contrib/libosmium/osmium/util/config.hpp           |   72 +
 contrib/libosmium/osmium/util/data_file.hpp        |  194 ++
 contrib/libosmium/osmium/util/delta.hpp            |  174 ++
 contrib/libosmium/osmium/util/double.hpp           |   93 +
 contrib/libosmium/osmium/util/endian.hpp           |   45 +
 contrib/libosmium/osmium/util/file.hpp             |  121 +
 contrib/libosmium/osmium/util/memory_mapping.hpp   |  757 +++++++
 contrib/libosmium/osmium/util/minmax.hpp           |  120 +
 contrib/libosmium/osmium/util/options.hpp          |  165 ++
 contrib/libosmium/osmium/util/string.hpp           |  102 +
 contrib/libosmium/osmium/util/verbose_output.hpp   |  139 ++
 contrib/libosmium/osmium/visitor.hpp               |  258 +++
 contrib/libosmium/protozero/byteswap.hpp           |   69 +
 contrib/libosmium/protozero/exception.hpp          |   68 +
 contrib/libosmium/protozero/pbf_builder.hpp        |  137 ++
 contrib/libosmium/protozero/pbf_message.hpp        |   94 +
 contrib/libosmium/protozero/pbf_reader.hpp         | 1067 +++++++++
 contrib/libosmium/protozero/pbf_types.hpp          |   49 +
 contrib/libosmium/protozero/pbf_writer.hpp         |  666 ++++++
 contrib/libosmium/protozero/varint.hpp             |  132 ++
 contrib/libosmium/protozero/version.hpp            |   22 +
 default.style                                      |   19 +-
 docs/Doxyfile                                      | 2362 ++++++++++++++++++++
 docs/lua.md                                        |    4 +-
 docs/multi.md                                      |   54 +-
 docs/osm2pgsql.1                                   |   20 +-
 docs/pgsql.md                                      |    2 +-
 docs/usage.md                                      |   18 +-
 empty.style                                        |   58 +-
 expire-tiles.cpp                                   |   57 +-
 expire-tiles.hpp                                   |    2 +-
 geometry-builder.cpp                               |  691 +++---
 geometry-builder.hpp                               |   92 +-
 geometry-processor.cpp                             |   26 +-
 geometry-processor.hpp                             |   16 +-
 geos-fallback/geos/noding/SegmentNode.h            |  123 -
 geos-fallback/geos/noding/SegmentNodeList.h        |  204 --
 geos-fallback/geos/noding/SegmentString.h          |  224 --
 id-tracker.hpp                                     |   21 +-
 input.cpp                                          |  226 --
 input.hpp                                          |   14 -
 install-postgis-osm-db.sh                          |   12 +-
 install-postgis-osm-user.sh                        |    2 +-
 m4/ax_append_flag.m4                               |   71 -
 m4/ax_boost_base.m4                                |  285 ---
 m4/ax_boost_filesystem.m4                          |  118 -
 m4/ax_boost_system.m4                              |  120 -
 m4/ax_boost_thread.m4                              |  149 --
 m4/ax_cflags_warn_all.m4                           |  122 -
 m4/ax_compare_version.m4                           |  177 --
 m4/ax_compile_check_sizeof.m4                      |  114 -
 m4/ax_config_nice.m4                               |   37 -
 m4/ax_cxx_compile_stdcxx_11.m4                     |  142 --
 m4/ax_lib_bzip2.m4                                 |  221 --
 m4/ax_lib_geos.m4                                  |  161 --
 m4/ax_lib_postgresql.m4                            |  164 --
 m4/ax_lib_proj.m4                                  |  216 --
 m4/ax_lib_protobuf_c.m4                            |  257 ---
 m4/ax_lib_xml2.m4                                  |  150 --
 m4/ax_lib_zlib.m4                                  |  220 --
 m4/ax_lua.m4                                       |  664 ------
 m4/ax_pthread.m4                                   |  332 ---
 middle-pgsql.cpp                                   |  501 ++---
 middle-pgsql.hpp                                   |   55 +-
 middle-ram.cpp                                     |  114 +-
 middle-ram.hpp                                     |   93 +-
 middle.cpp                                         |    8 +-
 middle.hpp                                         |   62 +-
 multi.lua                                          |    2 +-
 node-persistent-cache-reader.cpp                   |   56 +-
 node-persistent-cache.cpp                          |   64 +-
 node-persistent-cache.hpp                          |   20 +-
 node-ram-cache.cpp                                 |   71 +-
 node-ram-cache.hpp                                 |   26 +-
 options.cpp                                        |  267 ++-
 options.hpp                                        |  120 +-
 osm2pgsql.cpp                                      |   67 +-
 osm2pgsql.spec.in                                  |   96 -
 osmdata.cpp                                        |  156 +-
 osmdata.hpp                                        |   10 +-
 osmtypes.hpp                                       |   31 +-
 output-gazetteer.cpp                               |  492 ++--
 output-gazetteer.hpp                               |   50 +-
 output-multi.cpp                                   |  116 +-
 output-multi.hpp                                   |   30 +-
 output-null.cpp                                    |    4 +-
 output-null.hpp                                    |    2 +-
 output-pgsql.cpp                                   |  315 +--
 output-pgsql.hpp                                   |   27 +-
 output.cpp                                         |   44 +-
 output.hpp                                         |   26 +-
 parse-o5m.cpp                                      |  962 --------
 parse-o5m.hpp                                      |   44 -
 parse-osmium.cpp                                   |  229 ++
 parse-osmium.hpp                                   |  145 ++
 parse-pbf.cpp                                      |  554 -----
 parse-pbf.hpp                                      |   67 -
 parse-xml2.cpp                                     |  414 ----
 parse-xml2.hpp                                     |   62 -
 parse.cpp                                          |  178 --
 parse.hpp                                          |   96 -
 pgsql.cpp                                          |   19 +-
 pgsql.hpp                                          |   10 +-
 processor-line.cpp                                 |    7 +-
 processor-line.hpp                                 |    2 +-
 processor-point.cpp                                |   14 +-
 processor-point.hpp                                |    2 +-
 processor-polygon.cpp                              |   13 +-
 processor-polygon.hpp                              |    4 +-
 protobuf/fileformat.proto                          |   30 -
 protobuf/osmformat.proto                           |  206 --
 reprojection.cpp                                   |  235 +-
 reprojection.hpp                                   |   71 +-
 sanitizer.hpp                                      |    8 -
 sprompt.cpp                                        |   13 +-
 style.lua                                          |   12 +-
 table.cpp                                          |  109 +-
 table.hpp                                          |   51 +-
 taginfo.cpp                                        |   11 +-
 taginfo_impl.hpp                                   |    3 +-
 tagtransform.cpp                                   |  133 +-
 tagtransform.hpp                                   |    2 +-
 tests/008-ch.osc.gz                                |  Bin 0 -> 110786 bytes
 tests/CMakeLists.txt                               |   69 +
 tests/common-cleanup.cpp                           |   21 +
 tests/common-cleanup.hpp                           |   21 +
 tests/common-pg.cpp                                |  146 +-
 tests/common-pg.hpp                                |   63 +-
 tests/common.hpp                                   |   22 +
 tests/hstore-match-only.osm                        |  323 +++
 tests/hstore-match-only.style                      |   31 +
 tests/liechtenstein-2013-08-03.osm.bz2             |  Bin 1061981 -> 0 bytes
 tests/middle-tests.cpp                             |   25 +-
 tests/mockups.hpp                                  |  116 +
 tests/regression-test.py                           |   41 +-
 tests/regression-test.sh                           |    3 +-
 tests/test-expire-tiles.cpp                        |    1 +
 tests/test-hstore-match-only.cpp                   |   92 +
 tests/test-middle-flat.cpp                         |   27 +-
 tests/test-middle-pgsql.cpp                        |   17 +-
 tests/test-options-database.cpp                    |   87 +
 ...st-parse-options.cpp => test-options-parse.cpp} |   73 +-
 tests/test-output-multi-line-storage.cpp           |   64 +-
 tests/test-output-multi-line.cpp                   |   91 +-
 tests/test-output-multi-point-multi-table.cpp      |   70 +-
 tests/test-output-multi-point.cpp                  |   62 +-
 tests/test-output-multi-poly-trivial.cpp           |   76 +-
 tests/test-output-multi-polygon.cpp                |   93 +-
 tests/test-output-multi-tags.cpp                   |   90 +-
 tests/test-output-pgsql-area.cpp                   |  107 +
 tests/test-output-pgsql-schema.cpp                 |  110 +
 tests/test-output-pgsql-tablespace.cpp             |   81 +-
 tests/test-output-pgsql-z_order.cpp                |  127 +-
 tests/test-output-pgsql.cpp                        |  325 +--
 tests/test-parse-diff.cpp                          |  126 ++
 tests/test-parse-xml2.cpp                          |   78 +-
 tests/test_output_pgsql_area.osm                   |   55 +
 325 files changed, 38842 insertions(+), 11272 deletions(-)

diff --git a/.gitignore b/.gitignore
index a4cd9b6..5b8d46d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,68 +1,4 @@
-*.o
-*~
-Makefile.in
-aclocal.m4
-autom4te.cache/
-config.guess
-config.h.in
-config.h.in~
-config.sub
-configure
-compile
-depcomp
-fileformat.pb-c.c
-fileformat.pb-c.h
-install-sh
-legacy/Makefile.in
-ltmain.sh
-m4/libtool.m4
-m4/ltoptions.m4
-m4/ltsugar.m4
-m4/ltversion.m4
-m4/lt~obsolete.m4
-missing
-nodecachefilereader
-osmformat.pb-c.c
-osmformat.pb-c.h
-osm2pgsql
+build
 
-Makefile
-config.h
-config.log
-config.nice
-config.status
-legacy/.deps/
-legacy/Makefile
-libtool
-.deps/
-stamp-h1
-INSTALL
-
-log
-test-driver
-test-suite.log
-tests/.dirstamp
-tests/test-parse-xml2
-tests/test-middle-ram
-tests/test-middle-pgsql
-tests/test-middle-flat
-tests/test-pgsql-escape
-tests/test-parse-options
-tests/test-output-multi-tags
-tests/test-output-multi-line
-tests/test-output-multi-line-storage
-tests/test-output-multi-point
-tests/test-output-multi-point-multi-table
-tests/test-output-multi-polygon
-tests/test-output-multi-poly-trivial
-tests/test-output-pgsql
-tests/test-output-pgsql-tablespace
-tests/test-output-pgsql-z_order
-tests/test-expire-tiles
-tests/*.log
-tests/*.trs
-tests/*.flat.nodes.bin
-
-.libs/
-*.lo
-libosm2pgsql.la
+docs/html
+docs/latex
diff --git a/.travis.yml b/.travis.yml
index d339253..c5070e2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,74 +1,58 @@
 language: cpp
-
+sudo: false
 addons:
   apt:
+    sources:
+    - boost-latest
+    - ubuntu-toolchain-r-test
     packages:
-    - libtool
-    - libxml2-dev
+    - g++-4.8
+    - libexpat1-dev
     - libgeos-dev
     - libgeos++-dev
     - libpq-dev
     - libbz2-dev
     - libproj-dev
-    - protobuf-c-compiler
-    - libprotobuf-c0-dev
-
+    - lua5.2
+    - liblua5.2-dev
+    - libboost1.55-dev
+    - libboost-system1.55-dev
+    - libboost-filesystem1.55-dev
 matrix:
   include:
-    #basic tests of with/without lua and old boost versions, with both clang and gc
     - os: linux
       compiler: clang
-      env: USE_LUA=true
-    - os: linux
-      compiler: clang
-      env: USE_LUA=true BOOST_PPA=1.55
-    - os: linux
-      compiler: clang
-      env: USE_LUA=false BOOST_PPA=1.55
-    - os: linux
-      compiler: gcc
-      env: USE_LUA=true
+      env: CXXFLAGS="-pedantic -Werror"
     - os: linux
       compiler: gcc
-      env: USE_LUA=true BOOST_PPA=1.55
-    - os: linux
-      compiler: gcc
-      env: USE_LUA=false BOOST_PPA=1.55
-    # additional tests
-    - os: linux
+      env: RUNTEST="-L NoDB" CXXFLAGS="-pedantic -Werror"
+    - os: osx
       compiler: clang
-      env: USE_LUA=true BOOST_PPA=1.54
-
+      env: RUNTEST="-L NoDB" CXXFLAGS="-pedantic -Werror"
 before_install:
-  # BOOST_PPA is only set on linux
-  - if [ -z ${BOOST_PPA+x} ]; then
-      echo "Using system Boost";
-    else
-      echo "Using Boost PPA";
-      sudo add-apt-repository -y ppa:boost-latest/ppa;
-    fi
-  - if [[ $(uname -s) == 'Linux' ]]; then
-      sudo apt-get update -qq;
+  - if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
+      brew install lua;
     fi
+# update versions
 install:
-  - if [[ $(uname -s) == 'Linux' ]]; then
-      if [ -z ${BOOST_PPA+x} ]; then
-        sudo apt-get install -y -qq libboost1.48-all-dev;
-      else
-        sudo apt-get install -y -qq "boost${BOOST_PPA}";
-      fi;
-      if [[ "${USE_LUA}" = "true" ]]; then
-        sudo apt-get install -y -qq lua5.2 liblua5.2-dev;
-      fi;
-    fi;
+  - if [[ $CC == 'gcc' ]]; then
+      export CC=gcc-4.8;
+    fi
+  - if [[ $CXX == 'g++' ]]; then
+      export CXX=g++-4.8;
+    fi
 before_script:
+  - $CXX --version
   - xml2-config --version
   - geos-config --version
   - proj | head -n1
-  - if [ "${USE_LUA}" = "true" ]; then
-      lua -v;
-    fi;
+  - lua -v
 script:
-  ./autogen.sh && ./configure && make -j2
+  - mkdir build && cd build
+  - cmake .. -DBUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
+  - make -j2
+  - echo "Running tests that does not require PostgreSQL server"
+  - if [[ $RUNTEST ]]; then ctest -VV $RUNTEST; fi
 after_failure:
-  - cat config.log
+  - # rerun make, but verbosely
+    make VERBOSE=1
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..d38df30
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,266 @@
+set(PACKAGE osm2pgsql)
+set(PACKAGE_NAME osm2pgsql)
+set(PACKAGE_VERSION 0.90.0-RC1)
+
+cmake_minimum_required(VERSION 2.8.7)
+
+project(osm2pgsql)
+
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+
+set(DATA_DIR \"${CMAKE_INSTALL_PREFIX}/share/osm2pgsql\")
+
+option(BUILD_TESTS "Build test suite" OFF)
+
+if (NOT TESTING_TIMEOUT)
+  set(TESTING_TIMEOUT 1200)
+endif()
+
+if (NOT WIN32 AND NOT APPLE)
+  # No need for this path, just a workaround to make cmake check pass on all systems
+  set(PostgreSQL_TYPE_INCLUDE_DIR /usr/include)
+endif()
+
+# Just in case user installed RPMs from http://yum.postgresql.org/
+list(APPEND PostgreSQL_ADDITIONAL_SEARCH_PATHS /usr/pgsql-9.3 /usr/pgsql-9.4 /usr/pgsql-9.5)
+
+if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
+  message(FATAL_ERROR "In-source builds are not allowed, please use a separate build directory like `mkdir build && cd build && cmake ..`")
+endif()
+
+message(STATUS "Building osm2pgsql ${PACKAGE_VERSION}")
+
+if (NOT CMAKE_BUILD_TYPE)
+  set(CMAKE_BUILD_TYPE RelWithDebInfo)
+endif()
+
+set (CMAKE_CXX_STANDARD 11)
+set (CMAKE_CXX_EXTENSIONS Off)
+set (CMAKE_CXX_STANDARD_REQUIRED TRUE)
+
+if ( MSVC )
+  add_definitions(-D_CRT_SECURE_NO_WARNINGS -DNOMINMAX -wd4996)
+  set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099 /STACK:30000000")
+else()
+  add_definitions(-Wall)
+  add_definitions(-DBOOST_TEST_DYN_LINK)
+  if (CMAKE_VERSION VERSION_LESS 3.1)
+    add_definitions(-std=c++11)
+  endif ()
+endif()
+
+option(EXTERNAL_LIBOSMIUM "Do not use the bundled libosmium" OFF)
+
+#############################################################
+# Detect available headers and set global compiler options
+#############################################################
+
+include (CheckIncludeFiles)
+include (CheckFunctionExists)
+include (CheckTypeSize)
+
+add_definitions( -DOSM2PGSQL_DATADIR=${DATA_DIR} )
+add_definitions( -DFIXED_POINT )
+
+CHECK_INCLUDE_FILES (termios.h HAVE_TERMIOS_H)
+CHECK_INCLUDE_FILES (libgen.h HAVE_LIBGEN_H)
+CHECK_INCLUDE_FILES (unistd.h HAVE_UNISTD_H)
+CHECK_INCLUDE_FILES (sys/wait.h HAVE_SYS_WAIT_H)
+CHECK_INCLUDE_FILES (sys/time.h HAVE_SYS_TIME_H)
+CHECK_INCLUDE_FILES (sys/mman.h HAVE_MMAP)
+
+if (WIN32)
+  set(HAVE_LIBGEN_H FALSE)
+endif()
+
+CHECK_FUNCTION_EXISTS(lseek64 HAVE_LSEEK64)
+CHECK_FUNCTION_EXISTS(posix_fallocate HAVE_POSIX_FALLOCATE)
+CHECK_FUNCTION_EXISTS(posix_fadvise HAVE_POSIX_FADVISE)
+CHECK_FUNCTION_EXISTS(sync_file_range HAVE_SYNC_FILE_RANGE)
+CHECK_FUNCTION_EXISTS(fork HAVE_FORK)
+
+CHECK_TYPE_SIZE("off_t" SIZEOF_OFF_T)
+
+if (NOT WIN32 AND NOT APPLE AND NOT HAVE_LSEEK64 AND NOT SIZEOF_OFF_T EQUAL 8)
+  message(FATAL_ERROR "Flat nodes cache requires a 64 bit capable seek")
+endif()
+
+#############################################################
+# Find necessary libraries
+#############################################################
+
+if (NOT EXTERNAL_LIBOSMIUM)
+  set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/contrib/libosmium")
+endif()
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
+
+find_package(Osmium REQUIRED COMPONENTS io geos proj)
+include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS})
+
+find_package(Lua)
+if (LUA_FOUND)
+  include_directories(${LUA_INCLUDE_DIR})
+  set(HAVE_LUA 1)
+else()
+  message(STATUS "lua libraries not found. You will NOT be able to use lua scripts for tag transform.")
+endif()
+
+if (MSVC)
+  # Boost thread needs extra libraries
+  set(BOOST_EXTRA date_time chrono)
+endif()
+
+if (NOT Boost_ADDITIONAL_VERSIONS)
+  set(Boost_ADDITIONAL_VERSIONS "1.55;1.56;1.57;1.58;1.59;1.60;1.61")
+endif()
+
+# first try to find the version
+find_package(Boost 1.50 REQUIRED COMPONENTS system filesystem ${BOOST_EXTRA})
+include_directories(${Boost_INCLUDE_DIR})
+
+find_package(PostgreSQL REQUIRED)
+include_directories(${PostgreSQL_INCLUDE_DIRS})
+
+find_package(Threads)
+
+############### Libraries are found now ########################
+
+
+set (LIBS ${Boost_LIBRARIES} ${PostgreSQL_LIBRARY} ${OSMIUM_LIBRARIES})
+
+if (LUA_FOUND)
+  list(APPEND LIBS ${LUA_LIBRARIES})
+endif()
+
+if (WIN32)
+  list(APPEND LIBS ws2_32)
+  if (MSVC)
+    find_path(GETOPT_INCLUDE_DIR getopt.h)
+    find_library(GETOPT_LIBRARY NAMES wingetopt getopt )
+    if (GETOPT_INCLUDE_DIR AND GETOPT_LIBRARY)
+      include_directories(${GETOPT_INCLUDE_DIR})
+      list(APPEND LIBS ${GETOPT_LIBRARY})
+    else()
+      message(ERROR "Can not find getopt library for Windows. Please get it from https://github.com/alex85k/wingetopt or alternative source.")
+    endif()
+  endif()
+endif()
+
+message("Libraries used to build: " ${LIBS})
+
+list(APPEND LIBS ${CMAKE_DL_LIBS})
+
+if (CMAKE_SYSTEM_NAME STREQUAL Linux)
+  check_library_exists(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME_IN_RT)
+  if (HAVE_CLOCK_GETTIME_IN_RT)
+    list(APPEND LIBS rt)
+  endif()
+endif ()
+
+message("Active compiler flags:" ${CMAKE_CXX_FLAGS})
+
+#############################################################
+# Build the library and executable file
+#############################################################
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+
+if (NOT HAVE_UNISTD_H AND NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/unistd.h)
+   file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/unistd.h "// empty header\n")
+endif()
+
+set(osm2pgsql_lib_SOURCES
+  expire-tiles.cpp
+  geometry-builder.cpp
+  geometry-processor.cpp
+  id-tracker.cpp
+  middle-pgsql.cpp
+  middle-ram.cpp
+  middle.cpp
+  node-persistent-cache.cpp
+  node-ram-cache.cpp
+  options.cpp
+  osmdata.cpp
+  output-gazetteer.cpp
+  output-multi.cpp
+  output-null.cpp
+  output-pgsql.cpp
+  output.cpp
+  parse-osmium.cpp
+  pgsql.cpp
+  processor-line.cpp
+  processor-point.cpp
+  processor-polygon.cpp
+  reprojection.cpp
+  sprompt.cpp
+  table.cpp
+  taginfo.cpp
+  tagtransform.cpp
+  util.cpp
+  wildcmp.cpp
+  expire-tiles.hpp
+  geometry-builder.hpp
+  geometry-processor.hpp
+  id-tracker.hpp
+  middle-pgsql.hpp
+  middle-ram.hpp
+  middle.hpp
+  node-persistent-cache.hpp
+  node-ram-cache.hpp
+  options.hpp
+  osmdata.hpp
+  osmtypes.hpp
+  output-gazetteer.hpp
+  output-multi.hpp
+  output-null.hpp
+  output-pgsql.hpp
+  output.hpp
+  parse-osmium.hpp
+  pgsql.hpp
+  processor-line.hpp
+  processor-point.hpp
+  processor-polygon.hpp
+  reprojection.hpp
+  sprompt.hpp
+  table.hpp
+  taginfo.hpp
+  taginfo_impl.hpp
+  tagtransform.hpp
+  util.hpp
+  wildcmp.hpp
+)
+
+add_library(osm2pgsql_lib STATIC ${osm2pgsql_lib_SOURCES})
+set_target_properties(osm2pgsql_lib PROPERTIES OUTPUT_NAME osm2pgsql)
+
+add_executable(osm2pgsql osm2pgsql.cpp)
+target_link_libraries(osm2pgsql_lib ${LIBS})
+target_link_libraries(osm2pgsql osm2pgsql_lib ${LIBS})
+
+if (HAVE_SYS_TIME_H) # until node-persistent-cache-reader is translated to std::chrono
+  add_executable(node-persistent-cache-reader node-persistent-cache-reader.cpp)
+  target_link_libraries(node-persistent-cache-reader osm2pgsql_lib ${LIBS})
+endif()
+
+#############################################################
+# Build tests
+#############################################################
+
+enable_testing()
+include(CTest)
+
+if (BUILD_TESTS)
+  add_subdirectory(tests)
+else()
+  add_subdirectory(tests EXCLUDE_FROM_ALL)
+endif()
+
+
+#############################################################
+# Install
+#############################################################
+
+install(TARGETS osm2pgsql DESTINATION bin)
+install(FILES docs/osm2pgsql.1 DESTINATION share/man/man1)
+install(FILES default.style empty.style 900913.sql DESTINATION share/osm2pgsql)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5f4d0fa..47f305a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -13,9 +13,9 @@ Your pull requests will then be reviewed and discussed.
 ## History
 
 To understand the osm2pgsql code, it helps to know some history on it. Osm2pgsql
-was written in C in 2007 as a port of an older Python utility. In 2014 it was 
+was written in C in 2007 as a port of an older Python utility. In 2014 it was
 ported to C++ by MapQuest and the last C version was released as 0.86.0. In it's
-time, it has had varying contribution activity, including times with no 
+time, it has had varying contribution activity, including times with no
 maintainer or active developers.
 
 Parts of the codebase still clearly show their C origin and could use rewriting
@@ -24,7 +24,7 @@ in modern C++, making use of data structures in the standard library.
 ## Versioning
 
 Osm2pgsql uses a X.Y.Z version number, where Y tells you if you are on a stable
-or development series. Like the Linux Kernel, even numbers are stable and 
+or development series. Like the Linux Kernel, even numbers are stable and
 development versions are odd.
 
 Bugs and known issues are fixed on the main branch only. Exceptions may be made
@@ -32,7 +32,7 @@ for easy bug fixes, or if a patch backporting a fix is provided.
 
 ## Code style
 
-The current codebase is a mix of styles, but new code should be written in the 
+The current codebase is a mix of styles, but new code should be written in the
 [K&R 1TBS style](https://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS) with
 4 spaces indentation. Tabs should never be used in the C++ code.
 
@@ -60,6 +60,18 @@ int main(int argc, char *argv[])
 
 Names should use underscores, not camel case, with class/struct names ending in `_t`.
 
+Headers should be included in the order `config.h`, C++ standard library headers,
+C library headers, Boost headers, and last osm2pgsql files.
+
+## Documentation
+
+User documentation is stored in `docs/`. Pages on the OpenStreetMap wiki are
+known to be unreliable and outdated.
+
+There is some documentation in Doxygen-formatted comments. The documentation can
+be generated with ``doxygen docs/Doxyfile``. It is not yet hooked into the build
+scripts as most functions are not yet documented.
+
 ## Platforms targeted
 
 Ideally osm2pgsql should compile on Linux, OS X, FreeBSD and Windows. It is
@@ -99,5 +111,5 @@ needs testing in a pull request.
 ## Maintainers
 
 The current maintainers of osm2pgsql are [Sarah Hoffmann](https://github.com/lonvia/)
-and [Paul Norman](https://github.com/pnorman/). Sarah has more experience with 
+and [Paul Norman](https://github.com/pnorman/). Sarah has more experience with
 the gazetteer backend and Paul with the pgsql and multi backends.
diff --git a/Makefile.am b/Makefile.am
deleted file mode 100644
index c91d408..0000000
--- a/Makefile.am
+++ /dev/null
@@ -1,188 +0,0 @@
-ACLOCAL_AMFLAGS = -I m4
-AUTOMAKE_OPTIONS = subdir-objects
-
-bin_PROGRAMS = osm2pgsql nodecachefilereader
-noinst_LTLIBRARIES = libosm2pgsql.la
-
-osm2pgsql_SOURCES = osm2pgsql.cpp
-
-osm2pgsql_LDADD = libosm2pgsql.la
-
-libosm2pgsql_la_SOURCES = \
-	UTF8sanitizer.cpp \
-	expire-tiles.cpp \
-	geometry-builder.cpp \
-	geometry-processor.cpp \
-	id-tracker.cpp \
-	input.cpp \
-	middle.cpp \
-	middle-pgsql.cpp \
-	middle-ram.cpp \
-	node-persistent-cache.cpp \
-	node-ram-cache.cpp \
-	options.cpp \
-	osmdata.cpp \
-	output.cpp \
-	output-gazetteer.cpp \
-	output-multi.cpp \
-	output-null.cpp \
-	output-pgsql.cpp \
-	parse.cpp \
-	parse-o5m.cpp \
-	parse-pbf.cpp \
-	parse-xml2.cpp \
-	pgsql.cpp \
-	processor-line.cpp \
-	processor-point.cpp \
-	processor-polygon.cpp \
-	reprojection.cpp \
-	sprompt.cpp \
-	table.cpp \
-	taginfo.cpp \
-	tagtransform.cpp \
-	util.cpp \
-	wildcmp.cpp
-
-nodecachefilereader_SOURCES = node-persistent-cache-reader.cpp
-nodecachefilereader_LDADD = libosm2pgsql.la
-
-check_PROGRAMS = \
-	tests/test-parse-xml2 \
-	tests/test-middle-ram \
-	tests/test-middle-pgsql \
-	tests/test-middle-flat \
-	tests/test-output-multi-tags \
-	tests/test-output-multi-line \
-	tests/test-output-multi-line-storage \
-	tests/test-output-multi-point \
-	tests/test-output-multi-point-multi-table \
-	tests/test-output-multi-polygon \
-	tests/test-output-multi-poly-trivial \
-	tests/test-output-pgsql \
-	tests/test-output-pgsql-z_order \
-	tests/test-output-pgsql-tablespace \
-	tests/test-pgsql-escape \
-	tests/test-parse-options \
-	tests/test-expire-tiles
-
-tests_test_parse_xml2_SOURCES = tests/test-parse-xml2.cpp
-tests_test_parse_xml2_LDADD = libosm2pgsql.la
-tests_test_middle_ram_SOURCES = tests/test-middle-ram.cpp tests/middle-tests.cpp
-tests_test_middle_ram_LDADD = libosm2pgsql.la
-tests_test_middle_pgsql_SOURCES = tests/test-middle-pgsql.cpp tests/middle-tests.cpp tests/common-pg.cpp
-tests_test_middle_pgsql_LDADD = libosm2pgsql.la
-tests_test_middle_flat_SOURCES = tests/test-middle-flat.cpp tests/middle-tests.cpp tests/common-pg.cpp
-tests_test_middle_flat_LDADD = libosm2pgsql.la
-tests_test_output_multi_tags_SOURCES = tests/test-output-multi-tags.cpp tests/common-pg.cpp
-tests_test_output_multi_tags_LDADD = libosm2pgsql.la
-tests_test_output_multi_line_SOURCES = tests/test-output-multi-line.cpp tests/common-pg.cpp
-tests_test_output_multi_line_LDADD = libosm2pgsql.la
-tests_test_output_multi_line_storage_SOURCES = tests/test-output-multi-line-storage.cpp tests/common-pg.cpp
-tests_test_output_multi_line_storage_LDADD = libosm2pgsql.la
-tests_test_output_multi_point_SOURCES = tests/test-output-multi-point.cpp tests/common-pg.cpp
-tests_test_output_multi_point_LDADD = libosm2pgsql.la
-tests_test_output_multi_point_multi_table_SOURCES = tests/test-output-multi-point-multi-table.cpp tests/common-pg.cpp
-tests_test_output_multi_point_multi_table_LDADD = libosm2pgsql.la
-tests_test_output_multi_polygon_SOURCES = tests/test-output-multi-polygon.cpp tests/common-pg.cpp
-tests_test_output_multi_polygon_LDADD = libosm2pgsql.la
-tests_test_output_multi_poly_trivial_SOURCES = tests/test-output-multi-poly-trivial.cpp tests/common-pg.cpp
-tests_test_output_multi_poly_trivial_LDADD = libosm2pgsql.la
-tests_test_output_pgsql_SOURCES = tests/test-output-pgsql.cpp tests/common-pg.cpp
-tests_test_output_pgsql_LDADD = libosm2pgsql.la
-tests_test_output_pgsql_tablespace_SOURCES = tests/test-output-pgsql-tablespace.cpp tests/common-pg.cpp
-tests_test_output_pgsql_tablespace_LDADD = libosm2pgsql.la
-tests_test_output_pgsql_z_order_SOURCES = tests/test-output-pgsql-z_order.cpp tests/common-pg.cpp
-tests_test_output_pgsql_z_order_LDADD = libosm2pgsql.la
-tests_test_pgsql_escape_SOURCES = tests/test-pgsql-escape.cpp
-tests_test_pgsql_escape_LDADD = libosm2pgsql.la
-tests_test_parse_options_SOURCES = tests/test-parse-options.cpp
-tests_test_parse_options_LDADD = libosm2pgsql.la
-tests_test_expire_tiles_SOURCES = tests/test-expire-tiles.cpp
-tests_test_expire_tiles_LDADD = libosm2pgsql.la
-
-MOSTLYCLEANFILES = tests/test_middle_flat.flat.nodes.bin tests/test_output_pgsql_area_way.flat.nodes.bin
-
-TESTS = $(check_PROGRAMS) tests/regression-test.sh
-TEST_EXTENSIONS = .sh
-SH_LOG_COMPILER = sh
-
-if READER_PBF
-osm2pgsql_SOURCES += parse-pbf.hpp fileformat.pb-c.h osmformat.pb-c.h
-libosm2pgsql_la_SOURCES += parse-pbf.cpp fileformat.pb-c.c osmformat.pb-c.c
-
-fileformat.pb-c.c: protobuf/fileformat.proto
-	 $(AM_V_GEN) $(PROTOC_C) --proto_path=protobuf --c_out=. $<
-
-fileformat.pb-c.h: fileformat.pb-c.c
-	@if test ! -f $@; then \
-	  rm -f $<; \
-	  $(MAKE) $(AM_MAKEFLAGS) $<; \
-	else :; fi
-
-osmformat.pb-c.c: protobuf/osmformat.proto
-	 $(AM_V_GEN) $(PROTOC_C) --proto_path=protobuf --c_out=. $<
-
-osmformat.pb-c.h: osmformat.pb-c.c
-	@if test ! -f $@; then \
-	  rm -f $<; \
-	  $(MAKE) $(AM_MAKEFLAGS) $<; \
-	else :; fi
-
-BUILT_SOURCES = \
-  fileformat.pb-c.c fileformat.pb-c.h \
-  osmformat.pb-c.c osmformat.pb-c.h
-
-CLEANFILES = \
-  fileformat.pb-c.c fileformat.pb-c.h \
-  osmformat.pb-c.c osmformat.pb-c.h
-
-endif
-
-osm2pgsqldir = $(datadir)/osm2pgsql
-
-AM_CFLAGS = @PTHREAD_CFLAGS@ @LFS_CFLAGS@ @POSTGRESQL_CPPFLAGS@ @XML2_CFLAGS@ @BZIP2_CFLAGS@ @GEOS_CFLAGS@ @PROJ_CFLAGS@ @PROTOBUF_C_CFLAGS@ @ZLIB_CFLAGS@ -DOSM2PGSQL_DATADIR='"$(osm2pgsqldir)"' -DVERSION='"@PACKAGE_VERSION@"' @LUA_INCLUDE@
-AM_CPPFLAGS = @PTHREAD_CFLAGS@ @POSTGRESQL_CPPFLAGS@ @XML2_CFLAGS@ @BZIP2_CFLAGS@ @GEOS_CFLAGS@ @PROJ_CFLAGS@ -DOSM2PGSQL_DATADIR='"$(osm2pgsqldir)"' -Igeos-fallback @LUA_INCLUDE@ @BOOST_CPPFLAGS@
-
-GLOBAL_LDFLAGS = @PTHREAD_CFLAGS@ @ZLIB_LDFLAGS@ @ZLIB_LIBS@ @POSTGRESQL_LDFLAGS@ @POSTGRESQL_LIBS@ @XML2_LDFLAGS@ @BZIP2_LDFLAGS@ @BZIP2_LIBS@ @GEOS_LDFLAGS@ @GEOS_LIBS@ @PROJ_LDFLAGS@ @PROJ_LIBS@ @PROTOBUF_C_LDFLAGS@ @PROTOBUF_C_LIBS@ -L/usr/lib/x86_64-linux-gnu @LUA_LIB@ @BOOST_LDFLAGS@ @BOOST_FILESYSTEM_LIB@ @BOOST_SYSTEM_LIB@ @BOOST_THREAD_LIB@
-osm2pgsql_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_parse_xml2_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_middle_ram_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_middle_pgsql_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_middle_flat_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_output_multi_tags_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_output_multi_line_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_output_multi_line_storage_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_output_multi_point_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_output_multi_point_multi_table_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_output_multi_polygon_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_output_multi_poly_trivial_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_output_pgsql_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_output_pgsql_tablespace_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_output_pgsql_z_order_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_pgsql_escape_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_parse_options_LDADD += $(GLOBAL_LDFLAGS)
-tests_test_expire_tiles_LDADD += $(GLOBAL_LDFLAGS)
-nodecachefilereader_LDADD += $(GLOBAL_LDFLAGS)
-
-osm2pgsql_DATA = default.style 900913.sql
-
-man1_MANS = docs/osm2pgsql.1 docs/nodecachefilereader.1
-
-EXTRA_DIST = osm2pgsql.spec.in \
-             osm2pgsql.spec \
-             protobuf/fileformat.proto \
-             protobuf/osmformat.proto \
-             debian \
-             $(osm2pgsql_DATA)
-
-$(PACKAGE).spec: $(PACKAGE).spec.in
-	sed -e "s/@""PACKAGE""@/$(PACKAGE)/g; s/@""VERSION""@/$(VERSION)/g; s/@""SVN""@/`svnversion`/g;" $^ > $@
-
-rpm: dist-gzip
-	rpmbuild -ta $(distdir).tar.gz
-
-distclean-local:
-	@rm -f $(PACKAGE).spec
-	@rm -f config.nice
-
-test: check
diff --git a/NEWS b/NEWS
deleted file mode 100644
index 3c335af..0000000
--- a/NEWS
+++ /dev/null
@@ -1,10 +0,0 @@
-== 2010-11-06 Version 0.70.5 ==
-
-* missing libraries are now already detected by 'configure'
-  instead of only breaking the build at compile time later
-
-* the existing 'libxml2' and experimental 'primitive' XML
-  readers and a new 'pbf' reader for the Protobuf based
-  format are now all available in the main binary, 
-  selectable using the new -r|--input-reader command line
-  option
\ No newline at end of file
diff --git a/README.md b/README.md
index b601b8c..59abb1d 100644
--- a/README.md
+++ b/README.md
@@ -27,64 +27,84 @@ $ git clone git://github.com/openstreetmap/osm2pgsql.git
 
 ## Building ##
 
-Osm2pgsql uses the [GNU Build System](http://www.gnu.org/software/automake/manual/html_node/GNU-Build-System.html)
-to configure and build itself and requires 
+Osm2pgsql uses the cross-platform [CMake build system](https://cmake.org/)
+to configure and build itself and requires
 
-* [libxml2](http://xmlsoft.org/)
+Required libraries are
+
+* [expat](http://www.libexpat.org/)
 * [geos](http://geos.osgeo.org/)
 * [proj](http://proj.osgeo.org/)
 * [bzip2](http://www.bzip.org/)
 * [zlib](http://www.zlib.net/)
-* [Protocol Buffers](https://developers.google.com/protocol-buffers/)
+* [Boost libraries](http://www.boost.org/), including system and filesystem
 * [PostgreSQL](http://www.postgresql.org/) client libraries
 * [Lua](http://www.lua.org/) (Optional, used for [Lua tag transforms](docs/lua.md))
 
 It also requires access to a database server running
 [PostgreSQL](http://www.postgresql.org/) and [PostGIS](http://www.postgis.net/).
 
-Make sure you have installed the development packages for the 
-libraries mentioned in the requirements section and a C and C++
-compiler.
+Make sure you have installed the development packages for the libraries
+mentioned in the requirements section and a C++ compiler which supports C++11.
+Both GCC 4.8 and Clang 3.4 meet this requirement.
+
+First install the dependencies.
 
-To install on a Debian or Ubuntu system, first install the prerequisites:
+On a Debian or Ubuntu system, this can be done with:
 
 ```sh
-sudo apt-get install autoconf automake libtool make g++ libboost-dev \
-  libboost-system-dev libboost-filesystem-dev libboost-thread-dev libxml2-dev \
-  libgeos-dev libgeos++-dev libpq-dev libbz2-dev libproj-dev \
-  protobuf-c-compiler libprotobuf-c0-dev lua5.2 liblua5.2-dev
+sudo apt-get install make cmake g++ libboost-dev libboost-system-dev \
+  libboost-filesystem-dev libexpat1-dev zlib1g-dev \
+  libbz2-dev libpq-dev libgeos-dev libgeos++-dev libproj-dev lua5.2 \
+  liblua5.2-dev
 ```
 
-To install on a Fedora system, use
+On a Fedora system, use
+
+```sh
+sudo yum install cmake gcc-c++ boost-devel expat-devel zlib-devel bzip2-devel \
+  postgresql-devel geos-devel proj-devel proj-epsg lua-devel
+```
+
+On RedHat / CentOS first run `sudo yum install epel-release` then install
+dependencies like on Fedora.
+
+On a FreeBSD system, use
 
 ```sh
-sudo yum install gcc-c++ automake libtool boost-devel libxml2-devel \
-  bzip2-devel postgresql-devel geos-devel proj-devel lua-devel \
-  protobuf-c-devel
+pkg install devel/cmake devel/boost-libs textproc/expat2 \
+  databases/postgresql94-client graphics/geos graphics/proj lang/lua52
 ```
 
-To install on a FreeBSD system, use
+Once dependencies are installed, use CMake to build the Makefiles in a separate folder
 
 ```sh
-pkg install devel/git devel/autoconf devel/automake devel/gmake devel/libtool \
-  textproc/libxml2 graphics/geos graphics/proj databases/postgresql94-client \
-  devel/boost-libs devel/protobuf-c lang/lua52 devel/pkgconf
+mkdir build && cd build
+cmake ..
 ```
 
-Then you should be able to bootstrap the build system:
+If some installed dependencies are not found by CMake, more options may need
+to be set. Typically, setting `CMAKE_PREFIX_PATH` to a list of appropriate
+paths is sufficient.
 
-    ./autogen.sh
+When the Makefiles have been successfully built, compile with
 
-And then run the standard GNU build install:
+```sh
+make
+```
 
-    ./configure && make && make install
+The compiled files can be installed with
 
-Please see `./configure --help` for more options on how to control the build
-process.
+```sh
+sudo make install
+```
 
-On FreeBSD instead bootstrap and then run
+By default, the Release build with debug info is created and no tests are compiled.
+You can change that behavior by using additional options like following:
 
-    LUA_LIB=`pkg-config --libs lua-5.2` ./configure && gmake && gmake install
+```sh
+cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTS=ON
+```
 
 ## Usage ##
 
@@ -92,7 +112,7 @@ Osm2pgsql has one program, the executable itself, which has **43** command line
 options.
 
 Before loading into a database, the database must be created and the PostGIS
-and optionally hstore extensions must be loaded. A full guide to PostgreSQL
+and optional hstore extensions must be loaded. A full guide to PostgreSQL
 setup is beyond the scope of this readme, but with reasonably recent versions
 of PostgreSQL and PostGIS this can be done with
 
@@ -118,8 +138,7 @@ osm2pgsql -c -d gis --slim -C <cache size> \
   --flat-nodes <flat nodes> planet-latest.osm.pbf
 ```
 where
-* ``<cache size>`` is 24000 on machines with 32GiB or more RAM
-  or about 75% of memory in MiB on machines with less
+* ``<cache size>`` is about 75% of memory in MiB, to a maximum of about 30000. Additional RAM will not be used.
 * ``<flat nodes>`` is a location where a 24GiB file can be saved.
 
 The databases from either of these commands can be used immediately by
@@ -137,11 +156,8 @@ In addition to the standard [pgsql](docs/pgsql.md) backend designed for
 rendering there is also the [gazetteer](docs/gazetteer.md) database for
 geocoding, principally with [Nominatim](http://www.nominatim.org/), and the
 null backend for testing. For flexibility a new [multi](docs/multi.md)
-backend is also avialable which allows the configuration of custom
-postgres tables instead of those provided in the pgsql backend.
-
-Any questions should be directed at the osm dev list
-http://wiki.openstreetmap.org/index.php/Mailing_lists
+backend is also available which allows the configuration of custom
+PostgreSQL tables instead of those provided in the pgsql backend.
 
 ## Contributing ##
 
diff --git a/UTF8sanitizer.cpp b/UTF8sanitizer.cpp
deleted file mode 100644
index 604067d..0000000
--- a/UTF8sanitizer.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-#include <cstdlib>
-#include <cstdio>
-#include <cstring>
-
-#include "sanitizer.hpp"
-#include "input.hpp"
-
-int sanitizerClose(void *context);
-int sanitizerProcess(void *context, char *buffer, int len);
-
-
-/* UTF8sanitizer algorithm has some nasty edge cases when trying to operate
- * in a 'block at a time' mode. For example, in the following scenario:
- *
- * INPUT sequence is 2 buffers with a 6 byte char starting at X1
- *
- * [   len = 5   ]   [len = 1]
- * X1 X2 X3 X4 X5   X6
- *
- * OUTPUT: nothing is generated for first buffer
- * This will itself cause caller to assume EOF (hopefully normal reader will read >> 5 bytes).
- * subsequent read of len=1 whille return all 6 bytes potentially causing output buffer overflow (and overwriting input data)
- *
- * The solution is to provice a small output buffer to hold anything bigger than a single byte
- *
- */
-
-
-struct Context {
-    long long line;
-    long long chars1, chars2, chars3, chars4, chars5, chars6;
-    int state, current_size;
-    int long_char[6];
-    int out_char[10];
-    int pend;
-    int verbose;
-    Input *file;
-};
-
-
-int sanitizerClose(void *context)
-{
-    struct Context *ctx = (struct Context *)context;
-    int r = inputClose(ctx->file);
-
-    if (ctx->verbose) {
-        fprintf(stderr, "Summary:\n");
-        fprintf(stderr, "chars1: %lld\n", ctx->chars1);
-        fprintf(stderr, "chars2: %lld\n", ctx->chars2);
-        fprintf(stderr, "chars3: %lld\n", ctx->chars3);
-        fprintf(stderr, "chars4: %lld\n", ctx->chars4);
-        fprintf(stderr, "chars5: %lld\n", ctx->chars5);
-        fprintf(stderr, "chars6: %lld\n", ctx->chars6);
-        fprintf(stderr, "lines : %lld\n", ctx->line);
-    }
-
-    free(ctx);
-    return r;
-}
-
-xmlTextReaderPtr sanitizerOpen(const char *name)
-{
-    struct Context *ctx = (struct Context *)malloc(sizeof(*ctx));
-
-    if (!ctx)
-        return NULL;
-
-    memset(ctx, 0, sizeof(*ctx));
-    ctx->verbose = 0;
-    ctx->state = 1;
-    ctx->pend = 0;
-
-    ctx->file = inputOpen(name);
-    if (!ctx->file) {
-        fprintf(stderr, "Input reader create failed\n");
-        free(ctx);
-        return NULL;
-    }
-
-    return xmlReaderForIO(sanitizerProcess, sanitizerClose, (void *)ctx, NULL, NULL, 0);
-}
-
-
-int sanitizerProcess(void *context, char *buffer, int len)
-{
-  struct Context *ctx = (struct Context *)context;
-  int current_char, i, out = 0;
-
-  while (out < len) {
-      if (ctx->pend) {
-          buffer[out++] = ctx->out_char[--ctx->pend];
-          continue;
-      }
-
-      current_char=inputGetChar(ctx->file);
-      if (inputEof(ctx->file))
-          break;
-
-      if ((current_char & 128) == 0) {
-          /* Handle_ASCII_char(); */
-          if (current_char == '\n')
-              ctx->line++;
-          else
-              ctx->chars1++;
-          if (ctx->state != 1) {
-              if (ctx->verbose)
-                  fprintf(stderr, "Error at line %lld\n", ctx->line);
-              buffer[out++] = '_';
-              ctx->state = 1;
-          }
-          /*  buffer[out++] = current_char; */
-          ctx->out_char[ctx->pend++] = current_char;
-      } else if ((current_char & (128+64)) == 128) {
-          /* Handle_continue_char(); */
-          if(ctx->state > 1) {
-              ctx->state--;
-              if(ctx->state==1) {
-                  ctx->out_char[ctx->pend++] = current_char;
-                  for(i=ctx->current_size-1; i>0; i--) {
-                      ctx->out_char[ctx->pend++] = ctx->long_char[i-1];
-                  }
-              }
-          } else {
-              if (ctx->verbose)
-                  fprintf(stderr, "Error at line %lld\n", ctx->line);
-              buffer[out++] = '_';
-              ctx->state=1;
-          }
-      } else if ((current_char & (128+64+32)) == (128+64)) {
-          /* Handle_two_bytes(); */
-          ctx->state=2;
-          ctx->chars2++;
-          ctx->current_size=2;
-      } else if ((current_char & (128+64+32+16)) == (128+64+32)) {
-          /* Handle_three_bytes(); */
-          ctx->state=3;
-          ctx->chars3++;
-          ctx->current_size=3;
-      } else if ((current_char & (128+64+32+16+8)) == (128+64+32+16)) {
-          /* Handle_four_bytes(); */
-          ctx->state=4;
-          ctx->chars4++;
-          ctx->current_size=4;
-      } else if ((current_char & (128+64+32+16+8+4)) == (128+64+32+16+8)) {
-          /* Handle_five_bytes(); */
-          ctx->state=5;
-          ctx->chars5++;
-          ctx->current_size=5;
-      } else if ((current_char & (128+64+32+16+8+4+2)) == (128+64+32+16+8+4)) {
-          /* Handle_six_bytes(); */
-          ctx->state=6;
-          ctx->chars6++;
-          ctx->current_size=6;
-      }
-      if(ctx->state>1) {
-          ctx->long_char[ctx->current_size-ctx->state]=current_char;
-      }
-  }
-  return out;
-}
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..60f64e7
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,69 @@
+environment:
+  global:
+    PGUSER: postgres
+    PGPASSWORD: Password12!
+    BOOST_ROOT: c:\libs\boost
+    PREFIX: c:\libs
+    PSQL_ROOT: C:\Program Files\PostgreSQL\9.4
+    CMAKE_PREFIX_PATH: c:\libs;C:\Program Files\PostgreSQL\9.4
+    PYTHONPATH: c:\libs
+  matrix:
+  - configuration: Release
+
+# Operating system (build VM template)
+
+os: Visual Studio 2015
+
+services:
+#  - postgresql # enable when Postgis will be available
+
+# scripts that are called at very beginning, before repo cloning
+init:
+  - git config --global core.autocrlf input
+
+# clone directory
+clone_folder: c:\osm2pgsql
+
+clone_depth: 1
+
+platform: x64
+
+install:
+  # by default, all script lines are interpreted as batch
+  - cd c:\
+  - mkdir libs
+  - curl -O https://dl.dropboxusercontent.com/u/63393258/libs_osm2pgsql_%Configuration%.7z
+  - 7z x libs_osm2pgsql_%Configuration%.7z | find ":"
+
+build_script:
+  - mkdir c:\osm2pgsql\build
+  - cd c:\osm2pgsql\build
+  - echo Running cmake...
+  - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
+  - cmake .. -LA -G "NMake Makefiles" -DBOOST_ROOT=%BOOST_ROOT% -DCMAKE_BUILD_TYPE=%Configuration% -DCMAKE_INSTALL_PREFIX=%PREFIX% -DBoost_USE_STATIC_LIBS=ON -DBUILD_TESTS=ON -DBoost_ADDITIONAL_VERSIONS=1.57;1.58;1.59
+  - nmake
+  - mkdir osm2pgsql-bin
+  - copy /y *.exe osm2pgsql-bin
+  - copy /y ..\*.style osm2pgsql-bin
+  - copy /y ..\*.lua osm2pgsql-bin
+  - copy /y %PREFIX%\bin\lua.dll osm2pgsql-bin
+  - copy /y %PREFIX%\bin\geos.dll osm2pgsql-bin
+  - copy /y "%PSQL_ROOT%\bin\libpq.dll" osm2pgsql-bin
+  - copy /y "%PSQL_ROOT%\bin\libintl-8.dll" osm2pgsql-bin
+  - copy /y "%PSQL_ROOT%\bin\libeay32.dll" osm2pgsql-bin
+  - copy /y "%PSQL_ROOT%\bin\ssleay32.dll" osm2pgsql-bin
+  - 7z a c:\osm2pgsql\osm2pgsql_%Configuration%.zip osm2pgsql-bin -tzip
+
+test_script:
+  - set PATH=c:\osm2pgsql\build\osm2pgsql-bin;%PATH%
+  - cd c:\osm2pgsql\build
+  - ctest -VV -L NoDB
+#  - ctest -VV -LE FlatNodes # enable when Postgis will be available
+
+#deploy_script:
+#  - cd c:\build
+#  - curl -T osm2pgsql_%Configuration%.zip --user %ACCOUNT% https://webdav.yandex.ru/libs/osm2pgsql_%Configuration%.zip
+
+artifacts:
+  - path: osm2pgsql_Release.zip
+    name: osm2pgsql_Release.zip
diff --git a/autogen.sh b/autogen.sh
deleted file mode 100755
index 68341a5..0000000
--- a/autogen.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-autoreconf -vfi
diff --git a/cmake/FindLua.cmake b/cmake/FindLua.cmake
new file mode 100644
index 0000000..1c24416
--- /dev/null
+++ b/cmake/FindLua.cmake
@@ -0,0 +1,171 @@
+#.rst:
+# FindLua
+# -------
+#
+#
+#
+# Locate Lua library This module defines
+#
+# ::
+#
+#   LUA_FOUND          - if false, do not try to link to Lua
+#   LUA_LIBRARIES      - both lua and lualib
+#   LUA_INCLUDE_DIR    - where to find lua.h
+#   LUA_VERSION_STRING - the version of Lua found
+#   LUA_VERSION_MAJOR  - the major version of Lua
+#   LUA_VERSION_MINOR  - the minor version of Lua
+#   LUA_VERSION_PATCH  - the patch version of Lua
+#
+#
+#
+# Note that the expected include convention is
+#
+# ::
+#
+#   #include "lua.h"
+#
+# and not
+#
+# ::
+#
+#   #include <lua/lua.h>
+#
+# This is because, the lua location is not standardized and may exist in
+# locations other than lua/
+
+#=============================================================================
+# Copyright 2007-2009 Kitware, Inc.
+# Copyright 2013 Rolf Eike Beer <eike at sf-mail.de>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+unset(_lua_include_subdirs)
+unset(_lua_library_names)
+
+# this is a function only to have all the variables inside go away automatically
+function(set_lua_version_vars)
+    set(LUA_VERSIONS5 5.3 5.2 5.1 5.0)
+
+    if (Lua_FIND_VERSION_EXACT)
+        if (Lua_FIND_VERSION_COUNT GREATER 1)
+            set(lua_append_versions ${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR})
+        endif ()
+    elseif (Lua_FIND_VERSION)
+        # once there is a different major version supported this should become a loop
+        if (NOT Lua_FIND_VERSION_MAJOR GREATER 5)
+            if (Lua_FIND_VERSION_COUNT EQUAL 1)
+                set(lua_append_versions ${LUA_VERSIONS5})
+            else ()
+                foreach (subver IN LISTS LUA_VERSIONS5)
+                    if (NOT subver VERSION_LESS ${Lua_FIND_VERSION})
+                        list(APPEND lua_append_versions ${subver})
+                    endif ()
+                endforeach ()
+            endif ()
+        endif ()
+    else ()
+        # once there is a different major version supported this should become a loop
+        set(lua_append_versions ${LUA_VERSIONS5})
+    endif ()
+
+    foreach (ver IN LISTS lua_append_versions)
+        string(REGEX MATCH "^([0-9]+)\\.([0-9]+)$" _ver "${ver}")
+        list(APPEND _lua_include_subdirs
+             include/lua${CMAKE_MATCH_1}${CMAKE_MATCH_2}
+             include/lua${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
+             include/lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
+        )
+        list(APPEND _lua_library_names
+             lua${CMAKE_MATCH_1}${CMAKE_MATCH_2}
+             lua${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
+             lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
+        )
+    endforeach ()
+
+    set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE)
+    set(_lua_library_names "${_lua_library_names}" PARENT_SCOPE)
+endfunction(set_lua_version_vars)
+
+set_lua_version_vars()
+
+find_path(LUA_INCLUDE_DIR lua.h
+  HINTS
+    ENV LUA_DIR
+  PATH_SUFFIXES ${_lua_include_subdirs} include/lua include
+  PATHS
+  ~/Library/Frameworks
+  /Library/Frameworks
+  /sw # Fink
+  /opt/local # DarwinPorts
+  /opt/csw # Blastwave
+  /opt
+)
+unset(_lua_include_subdirs)
+
+find_library(LUA_LIBRARY
+  NAMES ${_lua_library_names} lua
+  HINTS
+    ENV LUA_DIR
+  PATH_SUFFIXES lib
+  PATHS
+  ~/Library/Frameworks
+  /Library/Frameworks
+  /sw
+  /opt/local
+  /opt/csw
+  /opt
+)
+unset(_lua_library_names)
+
+if (LUA_LIBRARY)
+    # include the math library for Unix
+    if (UNIX AND NOT APPLE AND NOT BEOS)
+        find_library(LUA_MATH_LIBRARY m)
+        set(LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}")
+    # For Windows and Mac, don't need to explicitly include the math library
+    else ()
+        set(LUA_LIBRARIES "${LUA_LIBRARY}")
+    endif ()
+endif ()
+
+if (LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h")
+    # At least 5.[012] have different ways to express the version
+    # so all of them need to be tested. Lua 5.2 defines LUA_VERSION
+    # and LUA_RELEASE as joined by the C preprocessor, so avoid those.
+    file(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_strings
+         REGEX "^#define[ \t]+LUA_(RELEASE[ \t]+\"Lua [0-9]|VERSION([ \t]+\"Lua [0-9]|_[MR])).*")
+
+    string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MAJOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MAJOR ";${lua_version_strings};")
+    if (LUA_VERSION_MAJOR MATCHES "^[0-9]+$")
+        string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MINOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MINOR ";${lua_version_strings};")
+        string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_RELEASE[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_PATCH ";${lua_version_strings};")
+        set(LUA_VERSION_STRING "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_PATCH}")
+    else ()
+        string(REGEX REPLACE ".*;#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
+        if (NOT LUA_VERSION_STRING MATCHES "^[0-9.]+$")
+            string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
+        endif ()
+        string(REGEX REPLACE "^([0-9]+)\\.[0-9.]*$" "\\1" LUA_VERSION_MAJOR "${LUA_VERSION_STRING}")
+        string(REGEX REPLACE "^[0-9]+\\.([0-9]+)[0-9.]*$" "\\1" LUA_VERSION_MINOR "${LUA_VERSION_STRING}")
+        string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]).*" "\\1" LUA_VERSION_PATCH "${LUA_VERSION_STRING}")
+    endif ()
+
+    unset(lua_version_strings)
+endif()
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if
+# all listed variables are TRUE
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua
+                                  REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR
+                                  VERSION_VAR LUA_VERSION_STRING)
+
+mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARY LUA_MATH_LIBRARY)
diff --git a/cmake/FindOsmium.cmake b/cmake/FindOsmium.cmake
new file mode 100644
index 0000000..5d383d8
--- /dev/null
+++ b/cmake/FindOsmium.cmake
@@ -0,0 +1,317 @@
+#----------------------------------------------------------------------
+#
+#  FindOsmium.cmake
+#
+#  Find the Libosmium headers and, optionally, several components needed for
+#  different Libosmium functions.
+#
+#----------------------------------------------------------------------
+#
+#  Usage:
+#
+#    Copy this file somewhere into your project directory, where cmake can
+#    find it. Usually this will be a directory called "cmake" which you can
+#    add to the CMake module search path with the following line in your
+#    CMakeLists.txt:
+#
+#      list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+#
+#    Then add the following in your CMakeLists.txt:
+#
+#      find_package(Osmium REQUIRED COMPONENTS <XXX>)
+#      include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS})
+#
+#    For the <XXX> substitute a space separated list of one or more of the
+#    following components:
+#
+#      pbf        - include libraries needed for PBF input and output
+#      xml        - include libraries needed for XML input and output
+#      io         - include libraries needed for any type of input/output
+#      geos       - include if you want to use any of the GEOS functions
+#      gdal       - include if you want to use any of the OGR functions
+#      proj       - include if you want to use any of the Proj.4 functions
+#      sparsehash - include if you use the sparsehash index
+#
+#    You can check for success with something like this:
+#
+#      if(NOT OSMIUM_FOUND)
+#          message(WARNING "Libosmium not found!\n")
+#      endif()
+#
+#----------------------------------------------------------------------
+#
+#  Variables:
+#
+#    OSMIUM_FOUND         - True if Osmium found.
+#    OSMIUM_INCLUDE_DIRS  - Where to find include files.
+#    OSMIUM_XML_LIBRARIES - Libraries needed for XML I/O.
+#    OSMIUM_PBF_LIBRARIES - Libraries needed for PBF I/O.
+#    OSMIUM_IO_LIBRARIES  - Libraries needed for XML or PBF I/O.
+#    OSMIUM_LIBRARIES     - All libraries Osmium uses somewhere.
+#
+#----------------------------------------------------------------------
+
+# Look for the header file.
+find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp
+    PATH_SUFFIXES include
+    PATHS
+        ../libosmium
+        ~/Library/Frameworks
+        /Library/Frameworks
+        /opt/local # DarwinPorts
+        /opt
+)
+
+set(OSMIUM_INCLUDE_DIRS "${OSMIUM_INCLUDE_DIR}")
+
+#----------------------------------------------------------------------
+#
+#  Check for optional components
+#
+#----------------------------------------------------------------------
+if(Osmium_FIND_COMPONENTS)
+    foreach(_component ${Osmium_FIND_COMPONENTS})
+        string(TOUPPER ${_component} _component_uppercase)
+        set(Osmium_USE_${_component_uppercase} TRUE)
+    endforeach()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'io' is an alias for 'pbf' and 'xml'
+if(Osmium_USE_IO)
+    set(Osmium_USE_PBF TRUE)
+    set(Osmium_USE_XML TRUE)
+endif()
+
+#----------------------------------------------------------------------
+# Component 'ogr' is an alias for 'gdal'
+if(Osmium_USE_OGR)
+    set(Osmium_USE_GDAL TRUE)
+endif()
+
+#----------------------------------------------------------------------
+# Component 'pbf'
+if(Osmium_USE_PBF)
+    find_package(ZLIB)
+    find_package(Threads)
+
+    list(APPEND OSMIUM_EXTRA_FIND_VARS ZLIB_FOUND Threads_FOUND)
+    if(ZLIB_FOUND AND Threads_FOUND)
+        list(APPEND OSMIUM_PBF_LIBRARIES
+            ${ZLIB_LIBRARIES}
+            ${CMAKE_THREAD_LIBS_INIT}
+        )
+        if(WIN32)
+            list(APPEND OSMIUM_PBF_LIBRARIES ws2_32)
+        endif()
+        list(APPEND OSMIUM_INCLUDE_DIRS
+            ${ZLIB_INCLUDE_DIR}
+        )
+    else()
+        message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.")
+    endif()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'xml'
+if(Osmium_USE_XML)
+    find_package(EXPAT)
+    find_package(BZip2)
+    find_package(ZLIB)
+    find_package(Threads)
+
+    list(APPEND OSMIUM_EXTRA_FIND_VARS EXPAT_FOUND BZIP2_FOUND ZLIB_FOUND Threads_FOUND)
+    if(EXPAT_FOUND AND BZIP2_FOUND AND ZLIB_FOUND AND Threads_FOUND)
+        list(APPEND OSMIUM_XML_LIBRARIES
+            ${EXPAT_LIBRARIES}
+            ${BZIP2_LIBRARIES}
+            ${ZLIB_LIBRARIES}
+            ${CMAKE_THREAD_LIBS_INIT}
+        )
+        list(APPEND OSMIUM_INCLUDE_DIRS
+            ${EXPAT_INCLUDE_DIR}
+            ${BZIP2_INCLUDE_DIR}
+            ${ZLIB_INCLUDE_DIR}
+        )
+    else()
+        message(WARNING "Osmium: Can not find some libraries for XML input/output, please install them or configure the paths.")
+    endif()
+endif()
+
+#----------------------------------------------------------------------
+list(APPEND OSMIUM_IO_LIBRARIES
+    ${OSMIUM_PBF_LIBRARIES}
+    ${OSMIUM_XML_LIBRARIES}
+)
+
+list(APPEND OSMIUM_LIBRARIES
+    ${OSMIUM_IO_LIBRARIES}
+)
+
+#----------------------------------------------------------------------
+# Component 'geos'
+if(Osmium_USE_GEOS)
+    find_path(GEOS_INCLUDE_DIR geos/geom.h)
+    find_library(GEOS_LIBRARY NAMES geos)
+
+    list(APPEND OSMIUM_EXTRA_FIND_VARS GEOS_INCLUDE_DIR GEOS_LIBRARY)
+    if(GEOS_INCLUDE_DIR AND GEOS_LIBRARY)
+        SET(GEOS_FOUND 1)
+        list(APPEND OSMIUM_LIBRARIES ${GEOS_LIBRARY})
+        list(APPEND OSMIUM_INCLUDE_DIRS ${GEOS_INCLUDE_DIR})
+    else()
+        message(WARNING "Osmium: GEOS library is required but not found, please install it or configure the paths.")
+    endif()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'gdal' (alias 'ogr')
+if(Osmium_USE_GDAL)
+    find_package(GDAL)
+
+    list(APPEND OSMIUM_EXTRA_FIND_VARS GDAL_FOUND)
+    if(GDAL_FOUND)
+        list(APPEND OSMIUM_LIBRARIES ${GDAL_LIBRARIES})
+        list(APPEND OSMIUM_INCLUDE_DIRS ${GDAL_INCLUDE_DIRS})
+    else()
+        message(WARNING "Osmium: GDAL library is required but not found, please install it or configure the paths.")
+    endif()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'proj'
+if(Osmium_USE_PROJ)
+    find_path(PROJ_INCLUDE_DIR proj_api.h)
+    find_library(PROJ_LIBRARY NAMES proj)
+
+    list(APPEND OSMIUM_EXTRA_FIND_VARS PROJ_INCLUDE_DIR PROJ_LIBRARY)
+    if(PROJ_INCLUDE_DIR AND PROJ_LIBRARY)
+        set(PROJ_FOUND 1)
+        list(APPEND OSMIUM_LIBRARIES ${PROJ_LIBRARY})
+        list(APPEND OSMIUM_INCLUDE_DIRS ${PROJ_INCLUDE_DIR})
+    else()
+        message(WARNING "Osmium: PROJ.4 library is required but not found, please install it or configure the paths.")
+    endif()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'sparsehash'
+if(Osmium_USE_SPARSEHASH)
+    find_path(SPARSEHASH_INCLUDE_DIR google/sparsetable)
+
+    list(APPEND OSMIUM_EXTRA_FIND_VARS SPARSEHASH_INCLUDE_DIR)
+    if(SPARSEHASH_INCLUDE_DIR)
+        # Find size of sparsetable::size_type. This does not work on older
+        # CMake versions because they can do this check only in C, not in C++.
+        if (NOT CMAKE_VERSION VERSION_LESS 3.0)
+           include(CheckTypeSize)
+           set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR})
+           set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable")
+           check_type_size("google::sparsetable<int>::size_type" SPARSETABLE_SIZE_TYPE LANGUAGE CXX)
+           set(CMAKE_EXTRA_INCLUDE_FILES)
+           set(CMAKE_REQUIRED_INCLUDES)
+        else()
+           set(SPARSETABLE_SIZE_TYPE ${CMAKE_SIZEOF_VOID_P})
+        endif()
+
+        # Sparsetable::size_type must be at least 8 bytes (64bit), otherwise
+        # OSM object IDs will not fit.
+        if(SPARSETABLE_SIZE_TYPE GREATER 7)
+            set(SPARSEHASH_FOUND 1)
+            add_definitions(-DOSMIUM_WITH_SPARSEHASH=${SPARSEHASH_FOUND})
+            list(APPEND OSMIUM_INCLUDE_DIRS ${SPARSEHASH_INCLUDE_DIR})
+        else()
+            message(WARNING "Osmium: Disabled Google SparseHash library on 32bit system (size_type=${SPARSETABLE_SIZE_TYPE}).")
+        endif()
+    else()
+        message(WARNING "Osmium: Google SparseHash library is required but not found, please install it or configure the paths.")
+    endif()
+endif()
+
+#----------------------------------------------------------------------
+
+list(REMOVE_DUPLICATES OSMIUM_INCLUDE_DIRS)
+
+if(OSMIUM_XML_LIBRARIES)
+    list(REMOVE_DUPLICATES OSMIUM_XML_LIBRARIES)
+endif()
+
+if(OSMIUM_PBF_LIBRARIES)
+    list(REMOVE_DUPLICATES OSMIUM_PBF_LIBRARIES)
+endif()
+
+if(OSMIUM_IO_LIBRARIES)
+    list(REMOVE_DUPLICATES OSMIUM_IO_LIBRARIES)
+endif()
+
+if(OSMIUM_LIBRARIES)
+    list(REMOVE_DUPLICATES OSMIUM_LIBRARIES)
+endif()
+
+#----------------------------------------------------------------------
+#
+#  Check that all required libraries are available
+#
+#----------------------------------------------------------------------
+if (OSMIUM_EXTRA_FIND_VARS)
+    list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS)
+endif()
+# Handle the QUIETLY and REQUIRED arguments and set OSMIUM_FOUND to TRUE if
+# all listed variables are TRUE.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Osmium REQUIRED_VARS OSMIUM_INCLUDE_DIR ${OSMIUM_EXTRA_FIND_VARS})
+unset(OSMIUM_EXTRA_FIND_VARS)
+
+#----------------------------------------------------------------------
+#
+#  Add compiler flags
+#
+#----------------------------------------------------------------------
+add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64)
+
+if(MSVC)
+    add_definitions(-wd4996)
+
+    # Disable warning C4068: "unknown pragma" because we want it to ignore
+    # pragmas for other compilers.
+    add_definitions(-wd4068)
+
+    # Disable warning C4715: "not all control paths return a value" because
+    # it generates too many false positives.
+    add_definitions(-wd4715)
+
+    # Disable warning C4351: new behavior: elements of array '...' will be
+    # default initialized. The new behaviour is correct and we don't support
+    # old compilers anyway.
+    add_definitions(-wd4351)
+
+    add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS)
+endif()
+
+if(APPLE)
+# following only available from cmake 2.8.12:
+#   add_compile_options(-stdlib=libc++)
+# so using this instead:
+    add_definitions(-stdlib=libc++)
+    set(LDFLAGS ${LDFLAGS} -stdlib=libc++)
+endif()
+
+#----------------------------------------------------------------------
+
+# This is a set of recommended warning options that can be added when compiling
+# libosmium code.
+if(MSVC)
+    set(OSMIUM_WARNING_OPTIONS "/W3 /wd4514" CACHE STRING "Recommended warning options for libosmium")
+else()
+    set(OSMIUM_WARNING_OPTIONS "-Wall -Wextra -pedantic -Wredundant-decls -Wdisabled-optimization -Wctor-dtor-privacy -Wnon-virtual-dtor -Woverloaded-virtual -Wsign-promo -Wold-style-cast" CACHE STRING "Recommended warning options for libosmium")
+endif()
+
+set(OSMIUM_DRACONIC_CLANG_OPTIONS "-Wdocumentation -Wunused-exception-parameter -Wmissing-declarations -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-unused-macros -Wno-exit-time-destructors -Wno-global-constructors -Wno-padded -Wno-switch-enum -Wno-missing-prototypes -Wno-weak-vtables -Wno-cast-align -Wno-float-equal")
+
+if(Osmium_DEBUG)
+    message(STATUS "OSMIUM_XML_LIBRARIES=" ${OSMIUM_XML_LIBRARIES})
+    message(STATUS "OSMIUM_PBF_LIBRARIES=" ${OSMIUM_PBF_LIBRARIES})
+    message(STATUS "OSMIUM_IO_LIBRARIES=" ${OSMIUM_IO_LIBRARIES})
+    message(STATUS "OSMIUM_LIBRARIES=" ${OSMIUM_LIBRARIES})
+    message(STATUS "OSMIUM_INCLUDE_DIRS=" ${OSMIUM_INCLUDE_DIRS})
+endif()
diff --git a/cmake/config.h.in b/cmake/config.h.in
new file mode 100644
index 0000000..292f0df
--- /dev/null
+++ b/cmake/config.h.in
@@ -0,0 +1,35 @@
+#cmakedefine HAVE_FORK 1
+#cmakedefine HAVE_LSEEK64 1
+#cmakedefine HAVE_LUA 1
+#cmakedefine HAVE_POSIX_FADVISE 1
+#cmakedefine HAVE_POSIX_FALLOCATE 1
+#cmakedefine HAVE_SYNC_FILE_RANGE 1
+#cmakedefine HAVE_TERMIOS_H 1
+#cmakedefine HAVE_LIBGEN_H 1
+#cmakedefine HAVE_SYS_WAIT_H 1
+#cmakedefine HAVE_UNISTD_H 1
+#cmakedefine SIZEOF_OFF_T ${SIZEOF_OFF_T}
+
+#ifdef _MSC_VER
+#include <BaseTsd.h>
+typedef SSIZE_T ssize_t;
+#endif
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+#define VERSION "@PACKAGE_VERSION@"
diff --git a/configure.ac b/configure.ac
deleted file mode 100644
index cdbedc8..0000000
--- a/configure.ac
+++ /dev/null
@@ -1,171 +0,0 @@
-dnl Process this file with autoconf to produce a configure script.
-AC_INIT(osm2pgsql, 0.88.1)
-
-dnl Required autoconf version
-AC_PREREQ(2.61)
-
-AX_CONFIG_NICE
-
-dnl Allow maintainer mode to be disabled (debian build scripts do this)
-AM_MAINTAINER_MODE([enable])
-
-dnl use automake to generate standard Makefiles
-AM_INIT_AUTOMAKE([1.9.6 dist-bzip2 std-options check-news])
-
-dnl use 'silent' make rules by default (disabled for now)
-dnl AM_INIT_AUTOMAKE([1.11 dist-bzip2 silent-rules])
-dnl AM_SILENT_RULES([yes])
-
-dnl Additional macro definitions are in here
-AC_CONFIG_MACRO_DIR([m4])
-
-dnl Generate configuration header file
-AC_CONFIG_HEADER(config.h)
-
-AC_GNU_SOURCE
-AC_HEADER_SYS_WAIT
-AC_FUNC_MMAP
-
-dnl Find C compiler
-dnl AC_PROG_CC_C99
-
-dnl Find C++ compiler
-AC_PROG_CXX
-AC_CHECK_PROG(HAVE_CXX, $CXX, yes, no)
-if test "$HAVE_CXX" = "no" 
-then
-  AC_MSG_ERROR([Could not find a c++ compiler]);
-fi
-
-AX_CFLAGS_WARN_ALL
-AX_CXXFLAGS_WARN_ALL
-
-dnl Make sure we have libtool installed
-AM_PROG_LIBTOOL
-
-LFS_CFLAGS=`getconf LFS_CFLAGS`
-AC_SUBST(LFS_CFLAGS)
-
-AC_CHECK_FUNC(lseek64,[AC_DEFINE(HAVE_LSEEK64, [1], [lseek64 is present])],[AX_COMPILE_CHECK_SIZEOF(off_t)])
-AC_CHECK_FUNCS([posix_fallocate posix_fadvise sync_file_range fork])
-
-dnl Check for libxml2 library
-AX_LIB_XML2
-if test "$HAVE_XML2" = "no" 
-then
-  AC_MSG_ERROR([required library not found]);
-fi
-
-dnl check for zlib library
-AX_LIB_ZLIB
-if test "$HAVE_ZLIB" = "no" 
-then
-  AC_MSG_ERROR([required library not found]);
-fi
-
-dnl Check for bzip2 library
-AX_LIB_BZIP2
-if test "$HAVE_BZIP2" = "no" 
-then
-  AC_MSG_ERROR([required library not found]);
-fi
-
-dnl Check for Geos library
-AX_LIB_GEOS([3.1])
-
-dnl Check for Proj library
-AX_LIB_PROJ
-if test "$HAVE_PROJ" = "no" 
-then
-  AC_MSG_ERROR([required library not found]);
-fi
-
-dnl Check for protobuf-c library and protoc-c binary
-AX_LIB_PROTOBUF_C([0.14])
-
-dnl Decide whether to include PBF import support
-BUILD_READER_PBF=no
-if test "$HAVE_PROTOBUF_C" = "yes"
-then
-  if test "$PROTOC_C" != "false"
-  then
-    BUILD_READER_PBF=yes
-    AC_DEFINE([BUILD_READER_PBF], [1], [Requirements for building the PBF reader are met])
-  fi
-fi
-AM_CONDITIONAL([READER_PBF], [test "$BUILD_READER_PBF" = "yes"])
-
-dnl Check for PostgresSQL client library
-AX_LIB_POSTGRESQL
-if test "x$POSTGRESQL_VERSION" = "x"
-then
-    AC_MSG_ERROR([postgresql client library not found])
-fi
-
-
-dnl Check for pthread library
-AX_PTHREAD(,[AC_MSG_ERROR([no])])
-
-dnl Check for Boost libraries
-AX_BOOST_BASE([1.48], , [AC_MSG_ERROR([cannot find Boost libraries, which are are required for building osm2pgsql. Please install libboost-dev.])])
-
-AX_BOOST_SYSTEM
-AX_BOOST_FILESYSTEM
-AX_BOOST_THREAD
-if test "x$BOOST_SYSTEM_LIB" = "x" -o "x$BOOST_FILESYSTEM_LIB" = "x" -o "x$BOOST_THREAD_LIB" = "x"
-then
-    AC_MSG_ERROR([One or more of the mandatory Boost libraries not found.])
-fi
-
-dnl Boost json parser in 1.49 has a bug when compiled with C++11
-dnl see https://svn.boost.org/trac/boost/ticket/6785
-AC_ARG_WITH([cxx11],
-  [AS_HELP_STRING([--without-cxx11],
-    [do not check for C++11-capable compiler (for testing only)])],
-    [],
-    [with_cxx11=yes])
-
-if test "x$with_cxx11" = "xyes"; then
-    AX_BOOST_BASE([1.50], [ AX_CXX_COMPILE_STDCXX_11(,optional) ], [])
-fi
-
-dnl Check for Lua libraries and headers
-AX_PROG_LUA([5.0],[],[
-    AX_LUA_HEADERS([
-        AX_LUA_LIBS([
-            AC_DEFINE([HAVE_LUA], [1], [Requirements for lua are met])
-            HAVE_LUA=yes
-        ],[AC_MSG_WARN([cannot find Lua libs])])
-    ],[AC_MSG_WARN([cannot find Lua includes])])
-],[AC_MSG_WARN([cannot find Lua interpreter])])
-
-dnl Enable fixed point
-AC_ARG_WITH([fixed-point],
-  [AS_HELP_STRING([--without-fixed-point],
-    [use double instead of fixed point floats for coordinates])],
-    [],
-    [AC_DEFINE([FIXED_POINT], [1], [Store +-20,000km Mercator co-ordinates as fixed point 32bit number with maximum precision])])
-
-dnl Generate Makefile
-AC_OUTPUT(Makefile)
-
-if test "$BUILD_READER_PBF" != "yes"
-then
-    AC_MSG_WARN([
-protobuf libraries not found. You will NOT be able to import PBF files.
-
-To enable PBF support, the protobuf library and compiler are required. 
-Look for packages named: libprotobuf-c0-dev protobuf-c-compiler
-])
-fi
-
-if test "$HAVE_LUA" != "yes"
-then
-    AC_MSG_WARN([
-lua libraries not found. You will NOT be able to use lua scripts for tag transform.
-
-To enable lua support, the lua interpreter and libraries are required. 
-Look for packages named: lua5.2 liblua5.2-dev
-])
-fi
-
diff --git a/contrib/libosmium/LICENSE.txt b/contrib/libosmium/LICENSE.txt
new file mode 100644
index 0000000..36b7cd9
--- /dev/null
+++ b/contrib/libosmium/LICENSE.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/contrib/libosmium/README.contrib b/contrib/libosmium/README.contrib
new file mode 100644
index 0000000..d6011be
--- /dev/null
+++ b/contrib/libosmium/README.contrib
@@ -0,0 +1,2 @@
+Source: https://github.com/osmcode/libosmium
+Revision: v2.5.1
diff --git a/contrib/libosmium/README.md b/contrib/libosmium/README.md
new file mode 100644
index 0000000..9ac5a70
--- /dev/null
+++ b/contrib/libosmium/README.md
@@ -0,0 +1,108 @@
+# Libosmium
+
+http://osmcode.org/libosmium
+
+A fast and flexible C++ library for working with OpenStreetMap data.
+
+[![Build Status](https://secure.travis-ci.org/osmcode/libosmium.png)](https://travis-ci.org/osmcode/libosmium)
+[![Build status](https://ci.appveyor.com/api/projects/status/mkbg6e6stdgq7c1b?svg=true)](https://ci.appveyor.com/project/Mapbox/libosmium)
+
+Libosmium is developed on Linux, but also works on OSX and Windows (with some
+limitations).
+
+There are a few applications that use the Osmium library in the examples
+directory. See the [osmium-contrib](http://github.com/osmcode/osmium-contrib)
+repository for more example code.
+
+## Prerequisites
+
+Because Libosmium uses many C++11 features you need a modern compiler and
+standard C++ library. Osmium needs at least GCC 4.8 or clang (LLVM) 3.4.
+(Some parts may work with older versions.)
+
+Different parts of Libosmium (and the applications built on top of it) need
+different libraries. You DO NOT NEED to install all of them, just install those
+you need for your programs.
+
+For details see the
+[list of dependencies](https://github.com/osmcode/libosmium/wiki/Libosmium-dependencies).
+
+The [protozero](https://github.com/mapbox/protozero) and
+[utf8-cpp](http://utfcpp.sourceforge.net/) header-only libraries are included
+in the libosmium repository.
+
+
+## Directories
+
+* benchmarks: Some benchmarks checking different parts of Libosmium.
+
+* cmake: CMake configuration scripts.
+
+* doc: Config for documentation.
+
+* examples: Osmium example applications.
+
+* include: C/C++ include files. All of Libosmium is in those header files
+  which are needed for building Osmium applications.
+
+* test: Tests (see below).
+
+
+## Building
+
+Osmium is a header-only library, so there is nothing to build for the
+library itself.
+
+But there are some tests and examples that can be build. Libosmium uses
+cmake:
+
+    mkdir build
+    cd build
+    cmake ..
+    make
+
+This will build the examples and tests. Call `ctest` to run the tests.
+
+For more see the
+[Libosmium Wiki](https://github.com/osmcode/libosmium/wiki/Building-Libosmium).
+
+
+## Testing
+
+See the
+[Libosmium Wiki](https://github.com/osmcode/libosmium/wiki/Testing-Libosmium)
+for instructions.
+
+
+## Osmium on 32bit Machines
+
+Osmium works well on 64 bit machines, but on 32 bit machines there are some
+problems. Be aware that not everything will work on 32 bit architectures.
+This is mostly due to the 64 bit needed for node IDs. Also Osmium hasn't been
+tested well on 32 bit systems. Here are some issues you might run into:
+
+* Google Sparsehash does not work on 32 bit machines in our use case.
+* The `mmap` system call is called with a `size_t` argument, so it can't
+  give you more than 4GByte of memory on 32 bit systems. This might be a
+  problem.
+
+Please report any issues you have and we might be able to solve them.
+
+
+## Switching from the old Osmium
+
+If you have been using the old version of Osmium at
+https://github.com/joto/osmium you might want to read about the
+[changes needed](https://github.com/osmcode/libosmium/wiki/Changes-from-old-versions-of-Osmium).
+
+
+## License
+
+Libosmium is available under the Boost Software License. See LICENSE.txt.
+
+
+## Authors
+
+Libosmium was mainly written and is maintained by Jochen Topf
+(jochen at topf.org). See the git commit log for other authors.
+
diff --git a/contrib/libosmium/osmium/area/assembler.hpp b/contrib/libosmium/osmium/area/assembler.hpp
new file mode 100644
index 0000000..87feea2
--- /dev/null
+++ b/contrib/libosmium/osmium/area/assembler.hpp
@@ -0,0 +1,787 @@
+#ifndef OSMIUM_AREA_ASSEMBLER_HPP
+#define OSMIUM_AREA_ASSEMBLER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <iostream>
+#include <iterator>
+#include <list>
+#include <set>
+#include <string>
+#include <map>
+#include <vector>
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/area.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/tags/filter.hpp>
+
+#include <osmium/area/detail/proto_ring.hpp>
+#include <osmium/area/detail/node_ref_segment.hpp>
+#include <osmium/area/detail/segment_list.hpp>
+#include <osmium/area/problem_reporter.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        using osmium::area::detail::ProtoRing;
+
+        struct AssemblerConfig {
+
+            osmium::area::ProblemReporter* problem_reporter;
+
+            // Enables debug output to stderr
+            bool debug;
+
+            explicit AssemblerConfig(osmium::area::ProblemReporter* pr = nullptr, bool d = false) :
+                problem_reporter(pr),
+                debug(d) {
+            }
+
+            /**
+             * Enable or disable debug output to stderr. This is for Osmium
+             * developers only.
+             */
+            void enable_debug_output(bool d = true) {
+                debug = d;
+            }
+
+        }; // struct AssemblerConfig
+
+        /**
+         * Assembles area objects from multipolygon relations and their
+         * members. This is called by the MultipolygonCollector object
+         * after all members have been collected.
+         */
+        class Assembler {
+
+            const AssemblerConfig m_config;
+
+            // The way segments
+            osmium::area::detail::SegmentList m_segment_list;
+
+            // The rings we are building from the way segments
+            std::list<ProtoRing> m_rings;
+
+            std::vector<ProtoRing*> m_outer_rings;
+            std::vector<ProtoRing*> m_inner_rings;
+
+            int m_inner_outer_mismatches { 0 };
+
+            bool debug() const {
+                return m_config.debug;
+            }
+
+            /**
+             * Checks whether the given NodeRefs have the same location.
+             * Uses the actual location for the test, not the id. If both
+             * have the same location, but not the same id, a problem
+             * point will be added to the list of problem points.
+             */
+            bool has_same_location(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) {
+                if (nr1.location() != nr2.location()) {
+                    return false;
+                }
+                if (nr1.ref() != nr2.ref()) {
+                    if (m_config.problem_reporter) {
+                        m_config.problem_reporter->report_duplicate_node(nr1.ref(), nr2.ref(), nr1.location());
+                    }
+                }
+                return true;
+            }
+
+            void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Way& way) const {
+                osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+                for (const osmium::Tag& tag : way.tags()) {
+                    tl_builder.add_tag(tag.key(), tag.value());
+                }
+            }
+
+            void add_common_tags(osmium::builder::TagListBuilder& tl_builder, std::set<const osmium::Way*>& ways) const {
+                std::map<std::string, size_t> counter;
+                for (const osmium::Way* way : ways) {
+                    for (const auto& tag : way->tags()) {
+                        std::string kv {tag.key()};
+                        kv.append(1, '\0');
+                        kv.append(tag.value());
+                        ++counter[kv];
+                    }
+                }
+
+                size_t num_ways = ways.size();
+                for (const auto& t_c : counter) {
+                    if (debug()) {
+                        std::cerr << "        tag " << t_c.first << " is used " << t_c.second << " times in " << num_ways << " ways\n";
+                    }
+                    if (t_c.second == num_ways) {
+                        size_t len = std::strlen(t_c.first.c_str());
+                        tl_builder.add_tag(t_c.first.c_str(), t_c.first.c_str() + len + 1);
+                    }
+                }
+            }
+
+            struct MPFilter : public osmium::tags::KeyFilter {
+
+                MPFilter() : osmium::tags::KeyFilter(true) {
+                    add(false, "type");
+                    add(false, "created_by");
+                    add(false, "source");
+                    add(false, "note");
+                    add(false, "test:id");
+                    add(false, "test:section");
+                }
+
+            }; // struct MPFilter
+
+            static MPFilter& filter() {
+                static MPFilter filter;
+                return filter;
+            }
+
+            void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Relation& relation) const {
+                const auto count = std::count_if(relation.tags().begin(), relation.tags().end(), filter());
+
+                if (debug()) {
+                    std::cerr << "  found " << count << " tags on relation (without ignored ones)\n";
+                }
+
+                if (count > 0) {
+                    if (debug()) {
+                        std::cerr << "    use tags from relation\n";
+                    }
+
+                    // write out all tags except type=*
+                    osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+                    for (const osmium::Tag& tag : relation.tags()) {
+                        if (strcmp(tag.key(), "type")) {
+                            tl_builder.add_tag(tag.key(), tag.value());
+                        }
+                    }
+                } else {
+                    if (debug()) {
+                        std::cerr << "    use tags from outer ways\n";
+                    }
+                    std::set<const osmium::Way*> ways;
+                    for (const auto& ring : m_outer_rings) {
+                        ring->get_ways(ways);
+                    }
+                    if (ways.size() == 1) {
+                        if (debug()) {
+                            std::cerr << "      only one outer way\n";
+                        }
+                        osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+                        for (const osmium::Tag& tag : (*ways.begin())->tags()) {
+                            tl_builder.add_tag(tag.key(), tag.value());
+                        }
+                    } else {
+                        if (debug()) {
+                            std::cerr << "      multiple outer ways, get common tags\n";
+                        }
+                        osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+                        add_common_tags(tl_builder, ways);
+                    }
+                }
+            }
+
+            /**
+             * Go through all the rings and find rings that are not closed.
+             * Problems are reported through the problem reporter.
+             *
+             * @returns true if any rings were not closed, false otherwise
+             */
+            bool check_for_open_rings() {
+                bool open_rings = false;
+
+                for (const auto& ring : m_rings) {
+                    if (!ring.closed()) {
+                        open_rings = true;
+                        if (m_config.problem_reporter) {
+                            m_config.problem_reporter->report_ring_not_closed(ring.get_segment_front().first().location(), ring.get_segment_back().second().location());
+                        }
+                    }
+                }
+
+                return open_rings;
+            }
+
+            /**
+             * Check whether there are any rings that can be combined with the
+             * given ring to one larger ring by appending the other ring to
+             * the end of this ring.
+             * If the rings can be combined they are and the function returns
+             * true.
+             */
+            bool possibly_combine_rings_back(ProtoRing& ring) {
+                const osmium::NodeRef& nr = ring.get_segment_back().second();
+
+                if (debug()) {
+                    std::cerr << "      possibly_combine_rings_back()\n";
+                }
+                for (auto it = m_rings.begin(); it != m_rings.end(); ++it) {
+                    if (&*it != &ring && !it->closed()) {
+                        if (has_same_location(nr, it->get_segment_front().first())) {
+                            if (debug()) {
+                                std::cerr << "      ring.last=it->first\n";
+                            }
+                            ring.merge_ring(*it, debug());
+                            m_rings.erase(it);
+                            return true;
+                        }
+                        if (has_same_location(nr, it->get_segment_back().second())) {
+                            if (debug()) {
+                                std::cerr << "      ring.last=it->last\n";
+                            }
+                            ring.merge_ring_reverse(*it, debug());
+                            m_rings.erase(it);
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            }
+
+            /**
+             * Check whether there are any rings that can be combined with the
+             * given ring to one larger ring by prepending the other ring to
+             * the start of this ring.
+             * If the rings can be combined they are and the function returns
+             * true.
+             */
+            bool possibly_combine_rings_front(ProtoRing& ring) {
+                const osmium::NodeRef& nr = ring.get_segment_front().first();
+
+                if (debug()) {
+                    std::cerr << "      possibly_combine_rings_front()\n";
+                }
+                for (auto it = m_rings.begin(); it != m_rings.end(); ++it) {
+                    if (&*it != &ring && !it->closed()) {
+                        if (has_same_location(nr, it->get_segment_back().second())) {
+                            if (debug()) {
+                                std::cerr << "      ring.first=it->last\n";
+                            }
+                            ring.swap_segments(*it);
+                            ring.merge_ring(*it, debug());
+                            m_rings.erase(it);
+                            return true;
+                        }
+                        if (has_same_location(nr, it->get_segment_front().first())) {
+                            if (debug()) {
+                                std::cerr << "      ring.first=it->first\n";
+                            }
+                            ring.reverse();
+                            ring.merge_ring(*it, debug());
+                            m_rings.erase(it);
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            }
+
+            void split_off_subring(osmium::area::detail::ProtoRing& ring, osmium::area::detail::ProtoRing::segments_type::iterator it, osmium::area::detail::ProtoRing::segments_type::iterator it_begin, osmium::area::detail::ProtoRing::segments_type::iterator it_end) {
+                if (debug()) {
+                    std::cerr << "        subring found at: " << *it << "\n";
+                }
+                ProtoRing new_ring(it_begin, it_end);
+                ring.remove_segments(it_begin, it_end);
+                if (debug()) {
+                    std::cerr << "        split into two rings:\n";
+                    std::cerr << "          " << new_ring << "\n";
+                    std::cerr << "          " << ring << "\n";
+                }
+                m_rings.push_back(std::move(new_ring));
+            }
+
+            bool has_closed_subring_back(ProtoRing& ring, const NodeRef& nr) {
+                if (ring.segments().size() < 3) {
+                    return false;
+                }
+                if (debug()) {
+                    std::cerr << "      has_closed_subring_back()\n";
+                }
+                const auto end = ring.segments().end();
+                for (auto it = ring.segments().begin() + 1; it != end - 1; ++it) {
+                    if (has_same_location(nr, it->first())) {
+                        split_off_subring(ring, it, it, end);
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            bool has_closed_subring_front(ProtoRing& ring, const NodeRef& nr) {
+                if (ring.segments().size() < 3) {
+                    return false;
+                }
+                if (debug()) {
+                    std::cerr << "      has_closed_subring_front()\n";
+                }
+                const auto end = ring.segments().end();
+                for (auto it = ring.segments().begin() + 1; it != end - 1; ++it) {
+                    if (has_same_location(nr, it->second())) {
+                        split_off_subring(ring, it, ring.segments().begin(), it+1);
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            bool check_for_closed_subring(ProtoRing& ring) {
+                if (debug()) {
+                    std::cerr << "      check_for_closed_subring()\n";
+                }
+
+                osmium::area::detail::ProtoRing::segments_type segments(ring.segments().size());
+                std::copy(ring.segments().begin(), ring.segments().end(), segments.begin());
+                std::sort(segments.begin(), segments.end());
+                const auto it = std::adjacent_find(segments.begin(), segments.end(), [this](const osmium::area::detail::NodeRefSegment& s1, const osmium::area::detail::NodeRefSegment& s2) {
+                    return has_same_location(s1.first(), s2.first());
+                });
+                if (it == segments.end()) {
+                    return false;
+                }
+                const auto r1 = std::find_first_of(ring.segments().begin(), ring.segments().end(), it, it+1);
+                assert(r1 != ring.segments().end());
+                const auto r2 = std::find_first_of(ring.segments().begin(), ring.segments().end(), it+1, it+2);
+                assert(r2 != ring.segments().end());
+
+                if (debug()) {
+                    std::cerr << "      found subring in ring " << ring << " at " << it->first() << "\n";
+                }
+
+                const auto m = std::minmax(r1, r2);
+
+                ProtoRing new_ring(m.first, m.second);
+                ring.remove_segments(m.first, m.second);
+
+                if (debug()) {
+                    std::cerr << "        split ring1=" << new_ring << "\n";
+                    std::cerr << "        split ring2=" << ring << "\n";
+                }
+
+                m_rings.emplace_back(new_ring);
+
+                return true;
+            }
+
+            void combine_rings_front(const osmium::area::detail::NodeRefSegment& segment, ProtoRing& ring) {
+                if (debug()) {
+                    std::cerr << " => match at front of ring\n";
+                }
+                ring.add_segment_front(segment);
+                has_closed_subring_front(ring, segment.first());
+                if (possibly_combine_rings_front(ring)) {
+                    check_for_closed_subring(ring);
+                }
+            }
+
+            void combine_rings_back(const osmium::area::detail::NodeRefSegment& segment, ProtoRing& ring) {
+                if (debug()) {
+                    std::cerr << " => match at back of ring\n";
+                }
+                ring.add_segment_back(segment);
+                has_closed_subring_back(ring, segment.second());
+                if (possibly_combine_rings_back(ring)) {
+                    check_for_closed_subring(ring);
+                }
+            }
+
+            /**
+             * Append each outer ring together with its inner rings to the
+             * area in the buffer.
+             */
+            void add_rings_to_area(osmium::builder::AreaBuilder& builder) const {
+                for (const ProtoRing* ring : m_outer_rings) {
+                    if (debug()) {
+                        std::cerr << "    ring " << *ring << " is outer\n";
+                    }
+                    {
+                        osmium::builder::OuterRingBuilder ring_builder(builder.buffer(), &builder);
+                        ring_builder.add_node_ref(ring->get_segment_front().first());
+                        for (const auto& segment : ring->segments()) {
+                            ring_builder.add_node_ref(segment.second());
+                        }
+                    }
+                    for (ProtoRing* inner : ring->inner_rings()) {
+                        osmium::builder::InnerRingBuilder ring_builder(builder.buffer(), &builder);
+                        ring_builder.add_node_ref(inner->get_segment_front().first());
+                        for (const auto& segment : inner->segments()) {
+                            ring_builder.add_node_ref(segment.second());
+                        }
+                    }
+                }
+            }
+
+            bool add_to_existing_ring(osmium::area::detail::NodeRefSegment segment) {
+                int n = 0;
+                for (auto& ring : m_rings) {
+                    if (debug()) {
+                        std::cerr << "    check against ring " << n << " " << ring;
+                    }
+                    if (ring.closed()) {
+                        if (debug()) {
+                            std::cerr << " => ring CLOSED\n";
+                        }
+                    } else {
+                        if (has_same_location(ring.get_segment_back().second(), segment.first())) {
+                            combine_rings_back(segment, ring);
+                            return true;
+                        }
+                        if (has_same_location(ring.get_segment_back().second(), segment.second())) {
+                            segment.swap_locations();
+                            combine_rings_back(segment, ring);
+                            return true;
+                        }
+                        if (has_same_location(ring.get_segment_front().first(), segment.first())) {
+                            segment.swap_locations();
+                            combine_rings_front(segment, ring);
+                            return true;
+                        }
+                        if (has_same_location(ring.get_segment_front().first(), segment.second())) {
+                            combine_rings_front(segment, ring);
+                            return true;
+                        }
+                        if (debug()) {
+                            std::cerr << " => no match\n";
+                        }
+                    }
+
+                    ++n;
+                }
+                return false;
+            }
+
+            void check_inner_outer(ProtoRing& ring) {
+                const osmium::NodeRef& min_node = ring.min_node();
+                if (debug()) {
+                    std::cerr << "    check_inner_outer min_node=" << min_node << "\n";
+                }
+
+                int count = 0;
+                int above = 0;
+
+                for (auto it = m_segment_list.begin(); it != m_segment_list.end() && it->first().location().x() <= min_node.location().x(); ++it) {
+                    if (!ring.contains(*it)) {
+                        if (debug()) {
+                            std::cerr << "      segments for count: " << *it;
+                        }
+                        if (it->to_left_of(min_node.location())) {
+                            ++count;
+                            if (debug()) {
+                                std::cerr << " counted\n";
+                            }
+                        } else {
+                            if (debug()) {
+                                std::cerr << " not counted\n";
+                            }
+                        }
+                        if (it->first().location() == min_node.location()) {
+                            if (it->second().location().y() > min_node.location().y()) {
+                                ++above;
+                            }
+                        }
+                        if (it->second().location() == min_node.location()) {
+                            if (it->first().location().y() > min_node.location().y()) {
+                                ++above;
+                            }
+                        }
+                    }
+                }
+
+                if (debug()) {
+                    std::cerr << "      count=" << count << " above=" << above << "\n";
+                }
+
+                count += above % 2;
+
+                if (count % 2) {
+                    ring.set_inner();
+                }
+            }
+
+            void check_inner_outer_roles() {
+                if (debug()) {
+                    std::cerr << "    check_inner_outer_roles\n";
+                }
+
+                for (const auto ringptr : m_outer_rings) {
+                    for (const auto& segment : ringptr->segments()) {
+                        if (!segment.role_outer()) {
+                            ++m_inner_outer_mismatches;
+                            if (debug()) {
+                                std::cerr << "      segment " << segment << " from way " << segment.way()->id() << " should have role 'outer'\n";
+                            }
+                            if (m_config.problem_reporter) {
+                                m_config.problem_reporter->report_role_should_be_outer(segment.way()->id(), segment.first().location(), segment.second().location());
+                            }
+                        }
+                    }
+                }
+                for (const auto ringptr : m_inner_rings) {
+                    for (const auto& segment : ringptr->segments()) {
+                        if (!segment.role_inner()) {
+                            ++m_inner_outer_mismatches;
+                            if (debug()) {
+                                std::cerr << "      segment " << segment << " from way " << segment.way()->id() << " should have role 'inner'\n";
+                            }
+                            if (m_config.problem_reporter) {
+                                m_config.problem_reporter->report_role_should_be_inner(segment.way()->id(), segment.first().location(), segment.second().location());
+                            }
+                        }
+                    }
+                }
+            }
+
+            /**
+             * Create rings from segments.
+             */
+            bool create_rings() {
+                m_segment_list.sort();
+                m_segment_list.erase_duplicate_segments();
+
+                // Now we look for segments crossing each other. If there are
+                // any, the multipolygon is invalid.
+                // In the future this could be improved by trying to fix those
+                // cases.
+                if (m_segment_list.find_intersections(m_config.problem_reporter)) {
+                    return false;
+                }
+
+                // Now iterator over all segments and add them to rings. Each segment
+                // is tacked on to either end of an existing ring if possible, or a
+                // new ring is started with it.
+                for (const auto& segment : m_segment_list) {
+                    if (debug()) {
+                        std::cerr << "  checking segment " << segment << "\n";
+                    }
+                    if (!add_to_existing_ring(segment)) {
+                        if (debug()) {
+                            std::cerr << "    new ring for segment " << segment << "\n";
+                        }
+                        m_rings.emplace_back(segment);
+                    }
+                }
+
+                if (debug()) {
+                    std::cerr << "  Rings:\n";
+                    for (const auto& ring : m_rings) {
+                        std::cerr << "    " << ring;
+                        if (ring.closed()) {
+                            std::cerr << " (closed)";
+                        }
+                        std::cerr << "\n";
+                    }
+                }
+
+                if (check_for_open_rings()) {
+                    if (debug()) {
+                        std::cerr << "  not all rings are closed\n";
+                    }
+                    return false;
+                }
+
+                if (debug()) {
+                    std::cerr << "  Find inner/outer...\n";
+                }
+
+                if (m_rings.size() == 1) {
+                    m_outer_rings.push_back(&m_rings.front());
+                } else {
+                    for (auto& ring : m_rings) {
+                        check_inner_outer(ring);
+                        if (ring.outer()) {
+                            if (!ring.is_cw()) {
+                                ring.reverse();
+                            }
+                            m_outer_rings.push_back(&ring);
+                        } else {
+                            if (ring.is_cw()) {
+                                ring.reverse();
+                            }
+                            m_inner_rings.push_back(&ring);
+                        }
+                    }
+
+                    if (m_outer_rings.size() == 1) {
+                        for (auto inner : m_inner_rings) {
+                            m_outer_rings.front()->add_inner_ring(inner);
+                        }
+                    } else {
+                        // sort outer rings by size, smallest first
+                        std::sort(m_outer_rings.begin(), m_outer_rings.end(), [](ProtoRing* a, ProtoRing* b) {
+                            return a->area() < b->area();
+                        });
+                        for (auto inner : m_inner_rings) {
+                            for (auto outer : m_outer_rings) {
+                                if (inner->is_in(outer)) {
+                                    outer->add_inner_ring(inner);
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+
+                check_inner_outer_roles();
+
+                return true;
+            }
+
+        public:
+
+            typedef osmium::area::AssemblerConfig config_type;
+
+            explicit Assembler(const config_type& config) :
+                m_config(config),
+                m_segment_list(config.debug) {
+            }
+
+            ~Assembler() = default;
+
+            /**
+             * Assemble an area from the given way.
+             * The resulting area is put into the out_buffer.
+             */
+            void operator()(const osmium::Way& way, osmium::memory::Buffer& out_buffer) {
+                if (m_config.problem_reporter) {
+                    m_config.problem_reporter->set_object(osmium::item_type::way, way.id());
+                }
+
+                if (!way.ends_have_same_id()) {
+                    if (m_config.problem_reporter) {
+                        m_config.problem_reporter->report_duplicate_node(way.nodes().front().ref(), way.nodes().back().ref(), way.nodes().front().location());
+                    }
+                }
+
+                m_segment_list.extract_segments_from_way(way, "outer");
+
+                if (debug()) {
+                    std::cerr << "\nBuild way id()=" << way.id() << " segments.size()=" << m_segment_list.size() << "\n";
+                }
+
+                // Now create the Area object and add the attributes and tags
+                // from the relation.
+                {
+                    osmium::builder::AreaBuilder builder(out_buffer);
+                    builder.initialize_from_object(way);
+
+                    if (create_rings()) {
+                        add_tags_to_area(builder, way);
+                        add_rings_to_area(builder);
+                    }
+                }
+                out_buffer.commit();
+            }
+
+            /**
+             * Assemble an area from the given relation and its members.
+             * All members are to be found in the in_buffer at the offsets
+             * given by the members parameter.
+             * The resulting area is put into the out_buffer.
+             */
+            void operator()(const osmium::Relation& relation, const std::vector<size_t>& members, const osmium::memory::Buffer& in_buffer, osmium::memory::Buffer& out_buffer) {
+                if (m_config.problem_reporter) {
+                    m_config.problem_reporter->set_object(osmium::item_type::relation, relation.id());
+                }
+
+                m_segment_list.extract_segments_from_ways(relation, members, in_buffer);
+
+                if (debug()) {
+                    std::cerr << "\nBuild relation id()=" << relation.id() << " members.size()=" << members.size() << " segments.size()=" << m_segment_list.size() << "\n";
+                }
+
+                size_t area_offset = out_buffer.committed();
+
+                // Now create the Area object and add the attributes and tags
+                // from the relation.
+                {
+                    osmium::builder::AreaBuilder builder(out_buffer);
+                    builder.initialize_from_object(relation);
+
+                    if (create_rings()) {
+                        add_tags_to_area(builder, relation);
+                        add_rings_to_area(builder);
+                    }
+                }
+                out_buffer.commit();
+
+                const osmium::TagList& area_tags = out_buffer.get<osmium::Area>(area_offset).tags(); // tags of the area we just built
+
+                // Find all closed ways that are inner rings and check their
+                // tags. If they are not the same as the tags of the area we
+                // just built, add them to a list and later build areas for
+                // them, too.
+                std::vector<const osmium::Way*> ways_that_should_be_areas;
+                if (m_inner_outer_mismatches == 0) {
+                    auto memit = relation.members().begin();
+                    for (size_t offset : members) {
+                        if (!std::strcmp(memit->role(), "inner")) {
+                            const osmium::Way& way = in_buffer.get<const osmium::Way>(offset);
+                            if (way.is_closed() && way.tags().size() > 0) {
+                                auto d = std::count_if(way.tags().begin(), way.tags().end(), filter());
+                                if (d > 0) {
+                                    osmium::tags::KeyFilter::iterator way_fi_begin(filter(), way.tags().begin(), way.tags().end());
+                                    osmium::tags::KeyFilter::iterator way_fi_end(filter(), way.tags().end(), way.tags().end());
+                                    osmium::tags::KeyFilter::iterator area_fi_begin(filter(), area_tags.begin(), area_tags.end());
+                                    osmium::tags::KeyFilter::iterator area_fi_end(filter(), area_tags.end(), area_tags.end());
+
+                                    if (!std::equal(way_fi_begin, way_fi_end, area_fi_begin) || d != std::distance(area_fi_begin, area_fi_end)) {
+                                        ways_that_should_be_areas.push_back(&way);
+                                    }
+                                }
+                            }
+                        }
+                        ++memit;
+                    }
+                }
+
+                // Now build areas for all ways found in the last step.
+                for (const osmium::Way* way : ways_that_should_be_areas) {
+                    Assembler assembler(m_config);
+                    assembler(*way, out_buffer);
+                }
+            }
+
+        }; // class Assembler
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_ASSEMBLER_HPP
diff --git a/contrib/libosmium/osmium/area/detail/node_ref_segment.hpp b/contrib/libosmium/osmium/area/detail/node_ref_segment.hpp
new file mode 100644
index 0000000..ec7b035
--- /dev/null
+++ b/contrib/libosmium/osmium/area/detail/node_ref_segment.hpp
@@ -0,0 +1,262 @@
+#ifndef OSMIUM_AREA_DETAIL_NODE_REF_SEGMENT_HPP
+#define OSMIUM_AREA_DETAIL_NODE_REF_SEGMENT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+#include <iosfwd>
+#include <utility>
+
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node_ref.hpp>
+
+namespace osmium {
+
+    class Way;
+
+    namespace area {
+
+        /**
+         * @brief Namespace for Osmium internal use
+         */
+        namespace detail {
+
+            /**
+             * This helper class for the Assembler class models a segment.
+             * Segments are the connection between
+             * two nodes and they all have their smaller coordinate at the
+             * beginning of the segment. Smaller, in this case, means smaller x
+             * coordinate, and if they are the same smaller y coordinate.
+             */
+            class NodeRefSegment {
+
+                osmium::NodeRef m_first;
+                osmium::NodeRef m_second;
+
+                /// Role of the member this segment was from.
+                const char* m_role;
+
+                /// Way this segment was from.
+                const osmium::Way* m_way;
+
+            public:
+
+                void swap_locations() {
+                    using std::swap;
+                    swap(m_first, m_second);
+                }
+
+                explicit NodeRefSegment() noexcept :
+                    m_first(),
+                    m_second(),
+                    m_role(nullptr),
+                    m_way(nullptr) {
+                }
+
+                explicit NodeRefSegment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2, const char* role, const osmium::Way* way) :
+                    m_first(nr1),
+                    m_second(nr2),
+                    m_role(role),
+                    m_way(way) {
+                    if (nr2.location() < nr1.location()) {
+                        swap_locations();
+                    }
+                }
+
+                NodeRefSegment(const NodeRefSegment&) = default;
+                NodeRefSegment(NodeRefSegment&&) = default;
+
+                NodeRefSegment& operator=(const NodeRefSegment&) = default;
+                NodeRefSegment& operator=(NodeRefSegment&&) = default;
+
+                ~NodeRefSegment() = default;
+
+                /// Return first NodeRef of Segment according to sorting order (bottom left to top right).
+                const osmium::NodeRef& first() const noexcept {
+                    return m_first;
+                }
+
+                /// Return second NodeRef of Segment according to sorting order (bottom left to top right).
+                const osmium::NodeRef& second() const noexcept {
+                    return m_second;
+                }
+
+                bool to_left_of(const osmium::Location& location) const {
+    //                std::cerr << "segment " << first() << "--" << second() << " to_left_of(" << location << "\n";
+
+                    if (first().location() == location || second().location() == location) {
+                        return false;
+                    }
+
+                    const std::pair<osmium::Location, osmium::Location> mm = std::minmax(first().location(), second().location(), [](const osmium::Location a, const osmium::Location b) {
+                        return a.y() < b.y();
+                    });
+
+                    if (mm.first.y() >= location.y() || mm.second.y() < location.y() || first().location().x() > location.x()) {
+    //                    std::cerr << "  false\n";
+                        return false;
+                    }
+
+                    int64_t ax = mm.first.x();
+                    int64_t bx = mm.second.x();
+                    int64_t lx = location.x();
+                    int64_t ay = mm.first.y();
+                    int64_t by = mm.second.y();
+                    int64_t ly = location.y();
+                    return ((bx - ax)*(ly - ay) - (by - ay)*(lx - ax)) <= 0;
+                }
+
+                bool role_outer() const noexcept {
+                    return !strcmp(m_role, "outer");
+                }
+
+                bool role_inner() const noexcept {
+                    return !strcmp(m_role, "inner");
+                }
+
+                const osmium::Way* way() const noexcept {
+                    return m_way;
+                }
+
+            }; // class NodeRefSegment
+
+            /// NodeRefSegments are equal if both their locations are equal
+            inline bool operator==(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+                return lhs.first().location() == rhs.first().location() && lhs.second().location() == rhs.second().location();
+            }
+
+            inline bool operator!=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+                return ! (lhs == rhs);
+            }
+
+            /**
+             * NodeRefSegments are "smaller" if they are to the left and down of another
+             * segment. The first() location is checked first() and only if they have the
+             * same first() location the second() location is taken into account.
+             */
+            inline bool operator<(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+                return (lhs.first().location() == rhs.first().location() && lhs.second().location() < rhs.second().location()) || lhs.first().location() < rhs.first().location();
+            }
+
+            inline bool operator>(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+                return rhs < lhs;
+            }
+
+            inline bool operator<=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+                return ! (rhs < lhs);
+            }
+
+            inline bool operator>=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+                return ! (lhs < rhs);
+            }
+
+            template <typename TChar, typename TTraits>
+            inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const NodeRefSegment& segment) {
+                return out << segment.first() << "--" << segment.second();
+            }
+
+            inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
+                if (s1.first().location().x() > s2.second().location().x()) {
+                    return true;
+                }
+                return false;
+            }
+
+            inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) {
+                const std::pair<int32_t, int32_t> m1 = std::minmax(s1.first().location().y(), s1.second().location().y());
+                const std::pair<int32_t, int32_t> m2 = std::minmax(s2.first().location().y(), s2.second().location().y());
+                if (m1.first > m2.second || m2.first > m1.second) {
+                    return false;
+                }
+                return true;
+            }
+
+            /**
+             * Calculate the intersection between to NodeRefSegments. The result is returned
+             * as a Location. Note that because the Location uses integers with limited
+             * precision internally, the result might be slightly different than the
+             * numerically correct location.
+             *
+             * If the segments touch in one of their endpoints, it doesn't count as an
+             * intersection.
+             *
+             * If the segments intersect not in a single point but in multiple points, ie
+             * if they overlap, this is NOT detected.
+             *
+             * @returns Undefined osmium::Location if there is no intersection or a defined
+             *          Location if the segments intersect.
+             */
+            inline osmium::Location calculate_intersection(const NodeRefSegment& s1, const NodeRefSegment& s2) {
+                if (s1.first().location()  == s2.first().location()  ||
+                    s1.first().location()  == s2.second().location() ||
+                    s1.second().location() == s2.first().location()  ||
+                    s1.second().location() == s2.second().location()) {
+                    return osmium::Location();
+                }
+
+                auto d = (static_cast<int64_t>(s2.second().y()) - static_cast<int64_t>(s2.first().y())) *
+                         (static_cast<int64_t>(s1.second().x()) - static_cast<int64_t>(s1.first().x())) -
+                         (static_cast<int64_t>(s2.second().x()) - static_cast<int64_t>(s2.first().x())) *
+                         (static_cast<int64_t>(s1.second().y()) - static_cast<int64_t>(s1.first().y()));
+
+                if (d != 0) {
+                    double denom  = ((s2.second().lat() - s2.first().lat())*(s1.second().lon() - s1.first().lon())) -
+                                    ((s2.second().lon() - s2.first().lon())*(s1.second().lat() - s1.first().lat()));
+
+                    double nume_a = ((s2.second().lon() - s2.first().lon())*(s1.first().lat() - s2.first().lat())) -
+                                    ((s2.second().lat() - s2.first().lat())*(s1.first().lon() - s2.first().lon()));
+
+                    double nume_b = ((s1.second().lon() - s1.first().lon())*(s1.first().lat() - s2.first().lat())) -
+                                    ((s1.second().lat() - s1.first().lat())*(s1.first().lon() - s2.first().lon()));
+
+                    if ((denom > 0 && nume_a >= 0 && nume_a <= denom && nume_b >= 0 && nume_b <= denom) ||
+                        (denom < 0 && nume_a <= 0 && nume_a >= denom && nume_b <= 0 && nume_b >= denom)) {
+                        double ua = nume_a / denom;
+                        double ix = s1.first().lon() + ua*(s1.second().lon() - s1.first().lon());
+                        double iy = s1.first().lat() + ua*(s1.second().lat() - s1.first().lat());
+                        return osmium::Location(ix, iy);
+                    }
+                }
+
+                return osmium::Location();
+            }
+
+        } // namespace detail
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_DETAIL_NODE_REF_SEGMENT_HPP
diff --git a/contrib/libosmium/osmium/area/detail/proto_ring.hpp b/contrib/libosmium/osmium/area/detail/proto_ring.hpp
new file mode 100644
index 0000000..162e289
--- /dev/null
+++ b/contrib/libosmium/osmium/area/detail/proto_ring.hpp
@@ -0,0 +1,277 @@
+#ifndef OSMIUM_AREA_DETAIL_PROTO_RING_HPP
+#define OSMIUM_AREA_DETAIL_PROTO_RING_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <iterator>
+#include <set>
+#include <vector>
+
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/area/detail/node_ref_segment.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        namespace detail {
+
+            /**
+             * A ring in the process of being built by the Assembler object.
+             */
+            class ProtoRing {
+
+            public:
+
+                typedef std::vector<NodeRefSegment> segments_type;
+
+            private:
+
+                // segments in this ring
+                segments_type m_segments;
+
+                bool m_outer {true};
+
+                // if this is an outer ring, these point to it's inner rings (if any)
+                std::vector<ProtoRing*> m_inner;
+
+            public:
+
+                explicit ProtoRing(const NodeRefSegment& segment) noexcept :
+                    m_segments() {
+                    add_segment_back(segment);
+                }
+
+                explicit ProtoRing(segments_type::const_iterator sbegin, segments_type::const_iterator send) :
+                    m_segments(static_cast<size_t>(std::distance(sbegin, send))) {
+                    std::copy(sbegin, send, m_segments.begin());
+                }
+
+                bool outer() const noexcept {
+                    return m_outer;
+                }
+
+                void set_inner() noexcept {
+                    m_outer = false;
+                }
+
+                segments_type& segments() noexcept {
+                    return m_segments;
+                }
+
+                const segments_type& segments() const noexcept {
+                    return m_segments;
+                }
+
+                void remove_segments(segments_type::iterator sbegin, segments_type::iterator send) {
+                    m_segments.erase(sbegin, send);
+                }
+
+                void add_segment_front(const NodeRefSegment& segment) {
+                    m_segments.insert(m_segments.begin(), segment);
+                }
+
+                void add_segment_back(const NodeRefSegment& segment) {
+                    m_segments.push_back(segment);
+                }
+
+                const NodeRefSegment& get_segment_front() const {
+                    return m_segments.front();
+                }
+
+                NodeRefSegment& get_segment_front() {
+                    return m_segments.front();
+                }
+
+                const NodeRefSegment& get_segment_back() const {
+                    return m_segments.back();
+                }
+
+                NodeRefSegment& get_segment_back() {
+                    return m_segments.back();
+                }
+
+                bool closed() const {
+                    return m_segments.front().first().location() == m_segments.back().second().location();
+                }
+
+                int64_t sum() const {
+                    int64_t sum = 0;
+
+                    for (const auto& segment : m_segments) {
+                        sum += static_cast<int64_t>(segment.first().location().x()) * static_cast<int64_t>(segment.second().location().y()) -
+                               static_cast<int64_t>(segment.second().location().x()) * static_cast<int64_t>(segment.first().location().y());
+                    }
+
+                    return sum;
+                }
+
+                bool is_cw() const {
+                    return sum() <= 0;
+                }
+
+                int64_t area() const {
+                    return std::abs(sum()) / 2;
+                }
+
+                void swap_segments(ProtoRing& other) {
+                    using std::swap;
+                    swap(m_segments, other.m_segments);
+                }
+
+                void add_inner_ring(ProtoRing* ring) {
+                    m_inner.push_back(ring);
+                }
+
+                const std::vector<ProtoRing*>& inner_rings() const {
+                    return m_inner;
+                }
+
+                void print(std::ostream& out) const {
+                    out << "[";
+                    bool first = true;
+                    for (const auto& segment : m_segments) {
+                        if (first) {
+                            out << segment.first().ref();
+                        }
+                        out << ',' << segment.second().ref();
+                        first = false;
+                    }
+                    out << "]";
+                }
+
+                void reverse() {
+                    std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment& segment) {
+                        segment.swap_locations();
+                    });
+                    std::reverse(m_segments.begin(), m_segments.end());
+                }
+
+                /**
+                 * Merge other ring to end of this ring.
+                 */
+                void merge_ring(const ProtoRing& other, bool debug) {
+                    if (debug) {
+                        std::cerr << "        MERGE rings ";
+                        print(std::cerr);
+                        std::cerr << " to ";
+                        other.print(std::cerr);
+                        std::cerr << "\n";
+                    }
+                    m_segments.insert(m_segments.end(), other.m_segments.begin(), other.m_segments.end());
+                    if (debug) {
+                        std::cerr << "          result ring: ";
+                        print(std::cerr);
+                        std::cerr << "\n";
+                    }
+                }
+
+                void merge_ring_reverse(const ProtoRing& other, bool debug) {
+                    if (debug) {
+                        std::cerr << "        MERGE rings (reverse) ";
+                        print(std::cerr);
+                        std::cerr << " to ";
+                        other.print(std::cerr);
+                        std::cerr << "\n";
+                    }
+                    size_t n = m_segments.size();
+                    m_segments.resize(n + other.m_segments.size());
+                    std::transform(other.m_segments.rbegin(), other.m_segments.rend(), m_segments.begin() + static_cast<segments_type::difference_type>(n), [](NodeRefSegment segment) {
+                        segment.swap_locations();
+                        return segment;
+                    });
+                    if (debug) {
+                        std::cerr << "          result ring: ";
+                        print(std::cerr);
+                        std::cerr << "\n";
+                    }
+                }
+
+                const NodeRef& min_node() const {
+                    auto it = std::min_element(m_segments.begin(), m_segments.end());
+                    if (location_less()(it->first(), it->second())) {
+                        return it->first();
+                    } else {
+                        return it->second();
+                    }
+                }
+
+                bool is_in(ProtoRing* outer) {
+                    osmium::Location testpoint = segments().front().first().location();
+                    bool is_in = false;
+
+                    for (size_t i = 0, j = outer->segments().size()-1; i < outer->segments().size(); j = i++) {
+                        if (((outer->segments()[i].first().location().y() > testpoint.y()) != (outer->segments()[j].first().location().y() > testpoint.y())) &&
+                            (testpoint.x() < (outer->segments()[j].first().location().x() - outer->segments()[i].first().location().x()) * (testpoint.y() - outer->segments()[i].first().location().y()) / (outer->segments()[j].first().location().y() - outer->segments()[i].first().location().y()) + outer->segments()[i].first().location().x()) ) {
+                            is_in = !is_in;
+                        }
+                    }
+
+                    return is_in;
+                }
+
+                void get_ways(std::set<const osmium::Way*>& ways) {
+                    for (const auto& segment : m_segments) {
+                        ways.insert(segment.way());
+                    }
+                }
+
+                bool contains(const NodeRefSegment& segment) const {
+                    for (const auto& s : m_segments) {
+                        if (s == segment || (s.first() == segment.second() && s.second() == segment.first())) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+
+            }; // class ProtoRing
+
+            template <typename TChar, typename TTraits>
+            inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const ProtoRing& ring) {
+                ring.print(out);
+                return out;
+            }
+
+        } // namespace detail
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_DETAIL_PROTO_RING_HPP
diff --git a/contrib/libosmium/osmium/area/detail/segment_list.hpp b/contrib/libosmium/osmium/area/detail/segment_list.hpp
new file mode 100644
index 0000000..289ecf0
--- /dev/null
+++ b/contrib/libosmium/osmium/area/detail/segment_list.hpp
@@ -0,0 +1,218 @@
+#ifndef OSMIUM_AREA_DETAIL_SEGMENT_LIST_HPP
+#define OSMIUM_AREA_DETAIL_SEGMENT_LIST_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <iostream>
+#include <vector>
+
+#include <osmium/area/problem_reporter.hpp>
+#include <osmium/area/detail/node_ref_segment.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        namespace detail {
+
+            /**
+             * This is a helper class for the area assembler. It models
+             * a list of segments.
+             */
+            class SegmentList {
+
+                typedef std::vector<NodeRefSegment> slist_type;
+
+                slist_type m_segments;
+
+                bool m_debug;
+
+            public:
+
+                explicit SegmentList(bool debug) noexcept :
+                    m_debug(debug) {
+                }
+
+                ~SegmentList() = default;
+
+                SegmentList(const SegmentList&) = delete;
+                SegmentList(SegmentList&&) = delete;
+
+                SegmentList& operator=(const SegmentList&) = delete;
+                SegmentList& operator=(SegmentList&&) = delete;
+
+                /// The number of segments in the list.
+                size_t size() const noexcept {
+                    return m_segments.size();
+                }
+
+                bool empty() const noexcept {
+                    return m_segments.empty();
+                }
+
+                typedef slist_type::const_iterator const_iterator;
+
+                const_iterator begin() const noexcept {
+                    return m_segments.begin();
+                }
+
+                const_iterator end() const noexcept {
+                    return m_segments.end();
+                }
+
+                /**
+                 * Enable or disable debug output to stderr. This is for Osmium
+                 * developers only.
+                 */
+                void enable_debug_output(bool debug = true) noexcept {
+                    m_debug = debug;
+                }
+
+                /// Clear the list of segments. All segments are removed.
+                void clear() {
+                    m_segments.clear();
+                }
+
+                /// Sort the list of segments.
+                void sort() {
+                    std::sort(m_segments.begin(), m_segments.end());
+                }
+
+                /**
+                 * Extract segments from given way and add them to the list.
+                 *
+                 * Segments connecting two nodes with the same location (ie same
+                 * node or different node with same location) are removed.
+                 *
+                 * XXX should two nodes with same location be reported?
+                 */
+                void extract_segments_from_way(const osmium::Way& way, const char* role) {
+                    osmium::NodeRef last_nr;
+                    for (const osmium::NodeRef& nr : way.nodes()) {
+                        if (last_nr.location() && last_nr.location() != nr.location()) {
+                            m_segments.emplace_back(last_nr, nr, role, &way);
+                        }
+                        last_nr = nr;
+                    }
+                }
+
+                /**
+                 * Extract all segments from all ways that make up this
+                 * multipolygon relation and add them to the list.
+                 */
+                void extract_segments_from_ways(const osmium::Relation& relation, const std::vector<size_t>& members, const osmium::memory::Buffer& in_buffer) {
+                    auto member_it = relation.members().begin();
+                    for (size_t offset : members) {
+                        const osmium::Way& way = in_buffer.get<const osmium::Way>(offset);
+                        extract_segments_from_way(way, member_it->role());
+                        ++member_it;
+                    }
+                }
+
+                /**
+                 * Find duplicate segments (ie same start and end point) in the
+                 * list and remove them. This will always remove pairs of the same
+                 * segment. So if there are three, for instance, two will be
+                 * removed and one will be left.
+                 */
+                void erase_duplicate_segments() {
+                    while (true) {
+                        auto it = std::adjacent_find(m_segments.begin(), m_segments.end());
+                        if (it == m_segments.end()) {
+                            return;
+                        }
+                        if (m_debug) {
+                            std::cerr << "  erase duplicate segment: " << *it << "\n";
+                        }
+                        m_segments.erase(it, it+2);
+                    }
+                }
+
+                /**
+                 * Find intersection between segments.
+                 *
+                 * @param problem_reporter Any intersections found are reported to this object.
+                 * @returns true if there are intersections.
+                 */
+                bool find_intersections(osmium::area::ProblemReporter* problem_reporter) const {
+                    if (m_segments.empty()) {
+                        return false;
+                    }
+
+                    bool found_intersections = false;
+
+                    for (auto it1 = m_segments.begin(); it1 != m_segments.end()-1; ++it1) {
+                        const NodeRefSegment& s1 = *it1;
+                        for (auto it2 = it1+1; it2 != m_segments.end(); ++it2) {
+                            const NodeRefSegment& s2 = *it2;
+
+                            assert(s1 != s2); // erase_duplicate_segments() should have made sure of that
+
+                            if (outside_x_range(s2, s1)) {
+                                break;
+                            }
+
+                            if (y_range_overlap(s1, s2)) {
+                                osmium::Location intersection = calculate_intersection(s1, s2);
+                                if (intersection) {
+                                    found_intersections = true;
+                                    if (m_debug) {
+                                        std::cerr << "  segments " << s1 << " and " << s2 << " intersecting at " << intersection << "\n";
+                                    }
+                                    if (problem_reporter) {
+                                        problem_reporter->report_intersection(s1.way()->id(), s1.first().location(), s1.second().location(), s2.way()->id(), s2.first().location(), s2.second().location(), intersection);
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                    return found_intersections;
+                }
+
+            }; // class SegmentList
+
+        } // namespace detail
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_DETAIL_SEGMENT_LIST_HPP
diff --git a/contrib/libosmium/osmium/area/multipolygon_collector.hpp b/contrib/libosmium/osmium/area/multipolygon_collector.hpp
new file mode 100644
index 0000000..c4155db
--- /dev/null
+++ b/contrib/libosmium/osmium/area/multipolygon_collector.hpp
@@ -0,0 +1,223 @@
+#ifndef OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
+#define OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <vector>
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/relations/collector.hpp>
+#include <osmium/relations/detail/member_meta.hpp>
+
+namespace osmium {
+
+    namespace relations {
+        class RelationMeta;
+    }
+
+    /**
+     * @brief Code related to the building of areas (multipolygons) from relations.
+     */
+    namespace area {
+
+        /**
+         * This class collects all data needed for creating areas from
+         * relations tagged with type=multipolygon or type=boundary.
+         * Most of its functionality is derived from the parent class
+         * osmium::relations::Collector.
+         *
+         * The actual assembling of the areas is done by the assembler
+         * class given as template argument.
+         *
+         * @tparam TAssembler Multipolygon Assembler class.
+         */
+        template <typename TAssembler>
+        class MultipolygonCollector : public osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> {
+
+            typedef typename osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> collector_type;
+
+            typedef typename TAssembler::config_type assembler_config_type;
+            const assembler_config_type m_assembler_config;
+
+            osmium::memory::Buffer m_output_buffer;
+
+            static constexpr size_t initial_output_buffer_size = 1024 * 1024;
+            static constexpr size_t max_buffer_size_for_flush = 100 * 1024;
+
+            void flush_output_buffer() {
+                if (this->callback()) {
+                    osmium::memory::Buffer buffer(initial_output_buffer_size);
+                    using std::swap;
+                    swap(buffer, m_output_buffer);
+                    this->callback()(std::move(buffer));
+                }
+            }
+
+            void possibly_flush_output_buffer() {
+                if (m_output_buffer.committed() > max_buffer_size_for_flush) {
+                    flush_output_buffer();
+                }
+            }
+
+        public:
+
+            explicit MultipolygonCollector(const assembler_config_type& assembler_config) :
+                collector_type(),
+                m_assembler_config(assembler_config),
+                m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) {
+            }
+
+            /**
+             * We are interested in all relations tagged with type=multipolygon
+             * or type=boundary.
+             *
+             * Overwritten from the base class.
+             */
+            bool keep_relation(const osmium::Relation& relation) const {
+                const char* type = relation.tags().get_value_by_key("type");
+
+                // ignore relations without "type" tag
+                if (!type) {
+                    return false;
+                }
+
+                if ((!strcmp(type, "multipolygon")) || (!strcmp(type, "boundary"))) {
+                    return true;
+                }
+
+                return false;
+            }
+
+            /**
+             * Overwritten from the base class.
+             */
+            bool keep_member(const osmium::relations::RelationMeta& /*relation_meta*/, const osmium::RelationMember& member) const {
+                // We are only interested in members of type way.
+                return member.type() == osmium::item_type::way;
+            }
+
+            /**
+             * This is called when a way is not in any multipolygon
+             * relation.
+             *
+             * Overwritten from the base class.
+             */
+            void way_not_in_any_relation(const osmium::Way& way) {
+                // you need at least 4 nodes to make up a polygon
+                if (way.nodes().size() <= 3) {
+                    return;
+                }
+                try {
+                    if (!way.nodes().front().location() || !way.nodes().back().location()) {
+                        throw osmium::invalid_location("invalid location");
+                    }
+                    if (way.ends_have_same_location()) {
+                        // way is closed and has enough nodes, build simple multipolygon
+                        TAssembler assembler(m_assembler_config);
+                        assembler(way, m_output_buffer);
+                        possibly_flush_output_buffer();
+                    }
+                } catch (osmium::invalid_location&) {
+                    // XXX ignore
+                }
+            }
+
+            void complete_relation(osmium::relations::RelationMeta& relation_meta) {
+                const osmium::Relation& relation = this->get_relation(relation_meta);
+                std::vector<size_t> offsets;
+                for (const auto& member : relation.members()) {
+                    if (member.ref() != 0) {
+                        offsets.push_back(this->get_offset(member.type(), member.ref()));
+                    }
+                }
+                try {
+                    TAssembler assembler(m_assembler_config);
+                    assembler(relation, offsets, this->members_buffer(), m_output_buffer);
+                    possibly_flush_output_buffer();
+                } catch (osmium::invalid_location&) {
+                    // XXX ignore
+                }
+
+                // clear member metas
+                for (const auto& member : relation.members()) {
+                    if (member.ref() != 0) {
+                        auto& mmv = this->member_meta(member.type());
+                        auto range = std::equal_range(mmv.begin(), mmv.end(), osmium::relations::MemberMeta(member.ref()));
+                        assert(range.first != range.second);
+
+                        // if this is the last time this object was needed
+                        // then mark it as removed
+                        if (osmium::relations::count_not_removed(range.first, range.second) == 1) {
+                            this->get_member(range.first->buffer_offset()).set_removed(true);
+                        }
+
+                        for (auto it = range.first; it != range.second; ++it) {
+                            if (!it->removed() && relation.id() == this->get_relation(it->relation_pos()).id()) {
+                                it->remove();
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+
+            void flush() {
+                flush_output_buffer();
+            }
+
+            osmium::memory::Buffer read() {
+                osmium::memory::Buffer buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes);
+
+                using std::swap;
+                swap(buffer, m_output_buffer);
+
+                return buffer;
+            }
+
+        }; // class MultipolygonCollector
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
diff --git a/contrib/libosmium/osmium/area/problem_reporter.hpp b/contrib/libosmium/osmium/area/problem_reporter.hpp
new file mode 100644
index 0000000..4ae4bb2
--- /dev/null
+++ b/contrib/libosmium/osmium/area/problem_reporter.hpp
@@ -0,0 +1,149 @@
+#ifndef OSMIUM_AREA_PROBLEM_REPORTER_HPP
+#define OSMIUM_AREA_PROBLEM_REPORTER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        /**
+         * When assembling a multipolygon/area from a multipolygon relation
+         * or a closed way several problems can be detected. This includes
+         * intersections between lines, wrong role attributes on relation
+         * members etc. These problems are reported by the area::Assembler
+         * class to the ProblemReporter class or one of its child classes.
+         *
+         * This is the parent class which does nothing with the reports.
+         * Child classes are expected to implement different ways of
+         * reporting the problems.
+         */
+        class ProblemReporter {
+
+        protected:
+
+            // Type of object we are currently working on
+            osmium::item_type m_object_type;
+
+            // ID of the relation/way we are currently working on
+            osmium::object_id_type m_object_id;
+
+        public:
+
+            ProblemReporter() = default;
+
+            virtual ~ProblemReporter() = default;
+
+            /**
+             * Set the object the next problem reports will be on.
+             *
+             * @param object_type The type of the object.
+             * @param object_id The ID of the object.
+             */
+            void set_object(osmium::item_type object_type, osmium::object_id_type object_id) noexcept {
+                m_object_type = object_type;
+                m_object_id = object_id;
+            }
+
+// Disable "unused-parameter" warning, so that the compiler will not complain.
+// We can't remove the parameter names, because then doxygen will complain.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
+            /**
+             * Report a duplicate node, ie. two nodes with the same location.
+             *
+             * @param node_id1       ID of the first node.
+             * @param node_id2       ID of the second node.
+             * @param location       Location of both nodes.
+             */
+            virtual void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) {
+            }
+
+            /**
+             * Report an intersection between two segments.
+             *
+             * @param way1_id        ID of the first involved way.
+             * @param way1_seg_start Location where the segment of the first way with the intersection starts
+             * @param way1_seg_end   Location where the segment of the first way with the intersection ends
+             * @param way2_id        ID of the second involved way.
+             * @param way2_seg_start Location where the segment of the second way with the intersection starts
+             * @param way2_seg_end   Location where the segment of the second way with the intersection ends
+             * @param intersection   Location of the intersection. This might be slightly off the correct location due to rounding.
+             */
+            virtual void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
+                                             osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) {
+            }
+
+            /**
+             * Report an open ring.
+             *
+             * @param end1           Location of the first open end.
+             * @param end2           Location of the second open end.
+             */
+            virtual void report_ring_not_closed(osmium::Location end1, osmium::Location end2) {
+            }
+
+            /**
+             * Report a segment that should have role "outer", but has a different role.
+             *
+             * @param way_id         ID of the way this segment is in.
+             * @param seg_start      Start of the segment with the wrong role.
+             * @param seg_end        End of the segment with the wrong role.
+             */
+            virtual void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
+            }
+
+            /**
+             * Report a segment that should have role "inner", but has a different role.
+             *
+             * @param way_id         ID of the way this segment is in.
+             * @param seg_start      Start of the segment with the wrong role.
+             * @param seg_end        End of the segment with the wrong role.
+             */
+            virtual void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
+            }
+
+#pragma GCC diagnostic pop
+
+        }; // class ProblemReporter
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_PROBLEM_REPORTER_HPP
diff --git a/contrib/libosmium/osmium/area/problem_reporter_exception.hpp b/contrib/libosmium/osmium/area/problem_reporter_exception.hpp
new file mode 100644
index 0000000..5e743c6
--- /dev/null
+++ b/contrib/libosmium/osmium/area/problem_reporter_exception.hpp
@@ -0,0 +1,96 @@
+#ifndef OSMIUM_AREA_PROBLEM_REPORTER_EXCEPTION_HPP
+#define OSMIUM_AREA_PROBLEM_REPORTER_EXCEPTION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <sstream>
+#include <stdexcept>
+
+#include <osmium/area/problem_reporter_stream.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        class ProblemReporterException : public ProblemReporterStream {
+
+            std::stringstream m_sstream;
+
+        public:
+
+            ProblemReporterException() :
+                ProblemReporterStream(m_sstream) {
+            }
+
+            virtual ~ProblemReporterException() = default;
+
+            void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
+                m_sstream.str();
+                ProblemReporterStream::report_duplicate_node(node_id1, node_id2, location);
+                throw std::runtime_error(m_sstream.str());
+            }
+
+            void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
+                                     osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
+                m_sstream.str();
+                ProblemReporterStream::report_intersection(way1_id, way1_seg_start, way1_seg_end, way2_id, way2_seg_start, way2_seg_end, intersection);
+                throw std::runtime_error(m_sstream.str());
+            }
+
+            void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
+                m_sstream.str();
+                ProblemReporterStream::report_ring_not_closed(end1, end2);
+                throw std::runtime_error(m_sstream.str());
+            }
+
+            void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+                m_sstream.str();
+                ProblemReporterStream::report_role_should_be_outer(way_id, seg_start, seg_end);
+                throw std::runtime_error(m_sstream.str());
+            }
+
+            void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+                m_sstream.str();
+                ProblemReporterStream::report_role_should_be_inner(way_id, seg_start, seg_end);
+                throw std::runtime_error(m_sstream.str());
+            }
+
+        }; // class ProblemReporterException
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_PROBLEM_REPORTER_EXCEPTION_HPP
diff --git a/contrib/libosmium/osmium/area/problem_reporter_ogr.hpp b/contrib/libosmium/osmium/area/problem_reporter_ogr.hpp
new file mode 100644
index 0000000..5332997
--- /dev/null
+++ b/contrib/libosmium/osmium/area/problem_reporter_ogr.hpp
@@ -0,0 +1,139 @@
+#ifndef OSMIUM_AREA_PROBLEM_REPORTER_OGR_HPP
+#define OSMIUM_AREA_PROBLEM_REPORTER_OGR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * This file contains code for reporting problems through OGR when
+ * assembling multipolygons.
+ *
+ * @attention If you include this file, you'll need to link with `libgdal`.
+ */
+
+#include <memory>
+
+#include <gdalcpp.hpp>
+
+#include <osmium/area/problem_reporter.hpp>
+#include <osmium/geom/factory.hpp>
+#include <osmium/geom/ogr.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        /**
+         * Report problems when assembling areas by adding them to
+         * layers in an OGR datasource.
+         */
+        class ProblemReporterOGR : public ProblemReporter {
+
+            osmium::geom::OGRFactory<> m_ogr_factory;
+
+            gdalcpp::Layer m_layer_perror;
+            gdalcpp::Layer m_layer_lerror;
+
+            void write_point(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location location) {
+                gdalcpp::Feature feature(m_layer_perror, m_ogr_factory.create_point(location));
+                feature.set_field("id1", static_cast<double>(id1));
+                feature.set_field("id2", static_cast<double>(id2));
+                feature.set_field("problem_type", problem_type);
+                feature.add_to_layer();
+            }
+
+            void write_line(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location loc1, osmium::Location loc2) {
+                std::unique_ptr<OGRPoint> ogr_point1 = m_ogr_factory.create_point(loc1);
+                std::unique_ptr<OGRPoint> ogr_point2 = m_ogr_factory.create_point(loc2);
+                std::unique_ptr<OGRLineString> ogr_linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
+                ogr_linestring->addPoint(ogr_point1.get());
+                ogr_linestring->addPoint(ogr_point2.get());
+
+                gdalcpp::Feature feature(m_layer_lerror, std::move(ogr_linestring));
+                feature.set_field("id1", static_cast<double>(id1));
+                feature.set_field("id2", static_cast<double>(id2));
+                feature.set_field("problem_type", problem_type);
+                feature.add_to_layer();
+            }
+
+        public:
+
+            explicit ProblemReporterOGR(gdalcpp::Dataset& dataset) :
+                m_layer_perror(dataset, "perrors", wkbPoint),
+                m_layer_lerror(dataset, "lerrors", wkbLineString) {
+
+                m_layer_perror.add_field("id1", OFTReal, 10);
+                m_layer_perror.add_field("id2", OFTReal, 10);
+                m_layer_perror.add_field("problem_type", OFTString, 30);
+
+                m_layer_lerror.add_field("id1", OFTReal, 10);
+                m_layer_lerror.add_field("id2", OFTReal, 10);
+                m_layer_lerror.add_field("problem_type", OFTString, 30);
+            }
+
+            virtual ~ProblemReporterOGR() = default;
+
+            void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
+                write_point("duplicate_node", node_id1, node_id2, location);
+            }
+
+            void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
+                                     osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
+                write_point("intersection", m_object_id, 0, intersection);
+                write_line("intersection", m_object_id, way1_id, way1_seg_start, way1_seg_end);
+                write_line("intersection", m_object_id, way2_id, way2_seg_start, way2_seg_end);
+            }
+
+            void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
+                write_point("ring_not_closed", m_object_id, 0, end1);
+                write_point("ring_not_closed", m_object_id, 0, end2);
+            }
+
+            void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+                write_line("role_should_be_outer", m_object_id, way_id, seg_start, seg_end);
+            }
+
+            void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+                write_line("role_should_be_inner", m_object_id, way_id, seg_start, seg_end);
+            }
+
+        }; // class ProblemReporterOGR
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_PROBLEM_REPORTER_OGR_HPP
diff --git a/contrib/libosmium/osmium/area/problem_reporter_stream.hpp b/contrib/libosmium/osmium/area/problem_reporter_stream.hpp
new file mode 100644
index 0000000..ddcb343
--- /dev/null
+++ b/contrib/libosmium/osmium/area/problem_reporter_stream.hpp
@@ -0,0 +1,96 @@
+#ifndef OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP
+#define OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <ostream>
+
+#include <osmium/area/problem_reporter.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    namespace area {
+
+        class ProblemReporterStream : public ProblemReporter {
+
+            std::ostream* m_out;
+
+        public:
+
+            explicit ProblemReporterStream(std::ostream& out) :
+                m_out(&out) {
+            }
+
+            virtual ~ProblemReporterStream() = default;
+
+            void header(const char* msg) {
+                *m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << ": ";
+            }
+
+            void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
+                header("duplicate node");
+                *m_out << "node_id1=" << node_id1 << " node_id2=" << node_id2 << " location=" << location << "\n";
+            }
+
+            void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
+                                     osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
+                header("intersection");
+                *m_out << "way1_id=" << way1_id << " way1_seg_start=" << way1_seg_start << " way1_seg_end=" << way1_seg_end
+                       << " way2_id=" << way2_id << " way2_seg_start=" << way2_seg_start << " way2_seg_end=" << way2_seg_end << " intersection=" << intersection << "\n";
+            }
+
+            void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
+                header("ring not closed");
+                *m_out << "end1=" << end1 << " end2=" << end2 << "\n";
+            }
+
+            void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+                header("role should be outer");
+                *m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n";
+            }
+
+            void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+                header("role should be inner");
+                *m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n";
+            }
+
+        }; // class ProblemReporterStream
+
+    } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP
diff --git a/contrib/libosmium/osmium/builder/builder.hpp b/contrib/libosmium/osmium/builder/builder.hpp
new file mode 100644
index 0000000..63eb4bb
--- /dev/null
+++ b/contrib/libosmium/osmium/builder/builder.hpp
@@ -0,0 +1,237 @@
+#ifndef OSMIUM_BUILDER_BUILDER_HPP
+#define OSMIUM_BUILDER_BUILDER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <new>
+#include <string>
+#include <type_traits>
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Classes for building OSM objects and other items in buffers
+     */
+    namespace builder {
+
+        class Builder {
+
+            osmium::memory::Buffer& m_buffer;
+            Builder* m_parent;
+            size_t m_item_offset;
+
+            Builder(const Builder&) = delete;
+            Builder(Builder&&) = delete;
+
+            Builder& operator=(const Builder&) = delete;
+            Builder& operator=(Builder&&) = delete;
+
+        protected:
+
+            explicit Builder(osmium::memory::Buffer& buffer, Builder* parent, osmium::memory::item_size_type size) :
+                m_buffer(buffer),
+                m_parent(parent),
+                m_item_offset(buffer.written()) {
+                m_buffer.reserve_space(size);
+                assert(buffer.is_aligned());
+                if (m_parent) {
+                    m_parent->add_size(size);
+                }
+            }
+
+            ~Builder() = default;
+
+            osmium::memory::Item& item() const {
+                return *reinterpret_cast<osmium::memory::Item*>(m_buffer.data() + m_item_offset);
+            }
+
+        public:
+
+            /**
+             * Add padding to buffer (if needed) to align data properly.
+             *
+             * This calculates how many padding bytes are needed and adds
+             * as many zero bytes to the buffer. It also adds this number
+             * to the size of the current item (if the "self" param is
+             * true) and recursively to all the parent items.
+             *
+             * @param self If true add number of padding bytes to size
+             *             of current item. Size is always added to
+             *             parent item (if any).
+             *
+             */
+            void add_padding(bool self = false) {
+                auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
+                if (padding != osmium::memory::align_bytes) {
+                    std::fill_n(m_buffer.reserve_space(padding), padding, 0);
+                    if (self) {
+                        add_size(padding);
+                    } else if (m_parent) {
+                        m_parent->add_size(padding);
+                        assert(m_parent->size() % osmium::memory::align_bytes == 0);
+                    }
+                }
+            }
+
+            void add_size(uint32_t size) {
+                item().add_size(size);
+                if (m_parent) {
+                    m_parent->add_size(size);
+                }
+            }
+
+            uint32_t size() const noexcept {
+                return item().byte_size();
+            }
+
+            void add_item(const osmium::memory::Item* item) {
+                unsigned char* target = m_buffer.reserve_space(item->padded_size());
+                std::copy_n(reinterpret_cast<const unsigned char*>(item), item->padded_size(), target);
+                add_size(item->padded_size());
+            }
+
+            /**
+             * Reserve space for an object of class T in buffer and return
+             * pointer to it.
+             */
+            template <typename T>
+            T* reserve_space_for() {
+                assert(m_buffer.is_aligned());
+                return reinterpret_cast<T*>(m_buffer.reserve_space(sizeof(T)));
+            }
+
+            /**
+             * Append data to buffer.
+             *
+             * @param data Pointer to data.
+             * @param length Length of data in bytes. If data is a
+             *               \0-terminated string, length must contain the
+             *               \0 byte.
+             * @returns The number of bytes appended (length).
+             */
+            osmium::memory::item_size_type append(const char* data, const osmium::memory::item_size_type length) {
+                unsigned char* target = m_buffer.reserve_space(length);
+                std::copy_n(reinterpret_cast<const unsigned char*>(data), length, target);
+                return length;
+            }
+
+            /**
+             * Append \0-terminated string to buffer.
+             *
+             * @param str \0-terminated string.
+             * @returns The number of bytes appended (strlen(str) + 1).
+             */
+            osmium::memory::item_size_type append(const char* str) {
+                return append(str, static_cast<osmium::memory::item_size_type>(std::strlen(str) + 1));
+            }
+
+            /**
+             * Append '\0' to the buffer.
+             *
+             * @returns The number of bytes appended (always 1).
+             */
+            osmium::memory::item_size_type append_zero() {
+                *m_buffer.reserve_space(1) = '\0';
+                return 1;
+            }
+
+            /// Return the buffer this builder is using.
+            osmium::memory::Buffer& buffer() noexcept {
+                return m_buffer;
+            }
+
+        }; // class Builder
+
+        template <typename TItem>
+        class ObjectBuilder : public Builder {
+
+            static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "ObjectBuilder can only build objects derived from osmium::memory::Item");
+
+        public:
+
+            explicit ObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
+                Builder(buffer, parent, sizeof(TItem)) {
+                new (&item()) TItem();
+            }
+
+            TItem& object() noexcept {
+                return static_cast<TItem&>(item());
+            }
+
+            /**
+             * Add user name to buffer.
+             *
+             * @param user Pointer to user name.
+             * @param length Length of user name (without \0 termination).
+             */
+            void add_user(const char* user, const string_size_type length) {
+                object().set_user_size(length + 1);
+                add_size(append(user, length) + append_zero());
+                add_padding(true);
+            }
+
+            /**
+             * Add user name to buffer.
+             *
+             * @param user Pointer to \0-terminated user name.
+             */
+            void add_user(const char* user) {
+                add_user(user, static_cast_with_assert<string_size_type>(std::strlen(user)));
+            }
+
+            /**
+             * Add user name to buffer.
+             *
+             * @param user User name.
+             */
+            void add_user(const std::string& user) {
+                add_user(user.data(), static_cast_with_assert<string_size_type>(user.size()));
+            }
+
+        }; // class ObjectBuilder
+
+    } // namespace builder
+
+} // namespace osmium
+
+#endif // OSMIUM_BUILDER_BUILDER_HPP
diff --git a/contrib/libosmium/osmium/builder/builder_helper.hpp b/contrib/libosmium/osmium/builder/builder_helper.hpp
new file mode 100644
index 0000000..eebdf33
--- /dev/null
+++ b/contrib/libosmium/osmium/builder/builder_helper.hpp
@@ -0,0 +1,103 @@
+#ifndef OSMIUM_BUILDER_BUILDER_HELPER_HPP
+#define OSMIUM_BUILDER_BUILDER_HELPER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <initializer_list>
+#include <functional>
+#include <map>
+#include <utility>
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/memory/buffer.hpp>
+
+namespace osmium {
+
+    class NodeRef;
+    class TagList;
+    class WayNodeList;
+
+    namespace builder {
+
+        inline const osmium::WayNodeList& build_way_node_list(osmium::memory::Buffer& buffer, const std::initializer_list<osmium::NodeRef>& nodes) {
+            size_t pos = buffer.committed();
+            {
+                osmium::builder::WayNodeListBuilder wnl_builder(buffer);
+                for (const auto& node_ref : nodes) {
+                    wnl_builder.add_node_ref(node_ref);
+                }
+            }
+            buffer.commit();
+            return buffer.get<const osmium::WayNodeList>(pos);
+        }
+
+        inline const osmium::TagList& build_tag_list(osmium::memory::Buffer& buffer, const std::initializer_list<std::pair<const char*, const char*>>& tags) {
+            size_t pos = buffer.committed();
+            {
+                osmium::builder::TagListBuilder tl_builder(buffer);
+                for (const auto& p : tags) {
+                    tl_builder.add_tag(p.first, p.second);
+                }
+            }
+            buffer.commit();
+            return buffer.get<const osmium::TagList>(pos);
+        }
+
+        inline const osmium::TagList& build_tag_list_from_map(osmium::memory::Buffer& buffer, const std::map<const char*, const char*>& tags) {
+            size_t pos = buffer.committed();
+            {
+                osmium::builder::TagListBuilder tl_builder(buffer);
+                for (const auto& p : tags) {
+                    tl_builder.add_tag(p.first, p.second);
+                }
+            }
+            buffer.commit();
+            return buffer.get<const osmium::TagList>(pos);
+        }
+
+        inline const osmium::TagList& build_tag_list_from_func(osmium::memory::Buffer& buffer, std::function<void(osmium::builder::TagListBuilder&)> func) {
+            size_t pos = buffer.committed();
+            {
+                osmium::builder::TagListBuilder tl_builder(buffer);
+                func(tl_builder);
+            }
+            buffer.commit();
+            return buffer.get<const osmium::TagList>(pos);
+        }
+
+    } // namespace builder
+
+} // namespace osmium
+
+#endif // OSMIUM_BUILDER_BUILDER_HELPER_HPP
diff --git a/contrib/libosmium/osmium/builder/osm_object_builder.hpp b/contrib/libosmium/osmium/builder/osm_object_builder.hpp
new file mode 100644
index 0000000..6aa43ac
--- /dev/null
+++ b/contrib/libosmium/osmium/builder/osm_object_builder.hpp
@@ -0,0 +1,370 @@
+#ifndef OSMIUM_BUILDER_OSM_OBJECT_BUILDER_HPP
+#define OSMIUM_BUILDER_OSM_OBJECT_BUILDER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstring>
+#include <initializer_list>
+#include <new>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include <osmium/builder/builder.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    namespace memory {
+        class Buffer;
+    }
+
+    namespace builder {
+
+        class TagListBuilder : public ObjectBuilder<TagList> {
+
+        public:
+
+            explicit TagListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
+                ObjectBuilder<TagList>(buffer, parent) {
+            }
+
+            ~TagListBuilder() {
+                add_padding();
+            }
+
+            /**
+             * Add tag to buffer.
+             *
+             * @param key Tag key (0-terminated string).
+             * @param value Tag value (0-terminated string).
+             */
+            void add_tag(const char* key, const char* value) {
+                if (std::strlen(key) > osmium::max_osm_string_length) {
+                    throw std::length_error("OSM tag key is too long");
+                }
+                if (std::strlen(value) > osmium::max_osm_string_length) {
+                    throw std::length_error("OSM tag value is too long");
+                }
+                add_size(append(key) + append(value));
+            }
+
+            /**
+             * Add tag to buffer.
+             *
+             * @param key Pointer to tag key.
+             * @param key_length Length of key (not including the \0 byte).
+             * @param value Pointer to tag value.
+             * @param value_length Length of value (not including the \0 byte).
+             */
+            void add_tag(const char* key, const size_t key_length, const char* value, const size_t value_length) {
+                if (key_length > osmium::max_osm_string_length) {
+                    throw std::length_error("OSM tag key is too long");
+                }
+                if (value_length > osmium::max_osm_string_length) {
+                    throw std::length_error("OSM tag value is too long");
+                }
+                add_size(append(key,   osmium::memory::item_size_type(key_length))   + append_zero() +
+                         append(value, osmium::memory::item_size_type(value_length)) + append_zero());
+            }
+
+            /**
+             * Add tag to buffer.
+             *
+             * @param key Tag key.
+             * @param value Tag value.
+             */
+            void add_tag(const std::string& key, const std::string& value) {
+                if (key.size() > osmium::max_osm_string_length) {
+                    throw std::length_error("OSM tag key is too long");
+                }
+                if (value.size() > osmium::max_osm_string_length) {
+                    throw std::length_error("OSM tag value is too long");
+                }
+                add_size(append(key.data(),   osmium::memory::item_size_type(key.size())   + 1) +
+                         append(value.data(), osmium::memory::item_size_type(value.size()) + 1));
+            }
+
+        }; // class TagListBuilder
+
+        template <typename T>
+        class NodeRefListBuilder : public ObjectBuilder<T> {
+
+        public:
+
+            explicit NodeRefListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
+                ObjectBuilder<T>(buffer, parent) {
+            }
+
+            ~NodeRefListBuilder() {
+                static_cast<Builder*>(this)->add_padding();
+            }
+
+            void add_node_ref(const NodeRef& node_ref) {
+                new (static_cast<Builder*>(this)->reserve_space_for<osmium::NodeRef>()) osmium::NodeRef(node_ref);
+                static_cast<Builder*>(this)->add_size(sizeof(osmium::NodeRef));
+            }
+
+            void add_node_ref(const object_id_type ref, const osmium::Location& location = Location{}) {
+                add_node_ref(NodeRef(ref, location));
+            }
+
+        }; // class NodeRefListBuilder
+
+        typedef NodeRefListBuilder<WayNodeList> WayNodeListBuilder;
+        typedef NodeRefListBuilder<OuterRing> OuterRingBuilder;
+        typedef NodeRefListBuilder<InnerRing> InnerRingBuilder;
+
+        class RelationMemberListBuilder : public ObjectBuilder<RelationMemberList> {
+
+            /**
+             * Add role to buffer.
+             *
+             * @param member Relation member object where the length of the role
+             *               will be set.
+             * @param role The role.
+             * @param length Length of role (without \0 termination).
+             * @throws std:length_error If role is longer than osmium::max_osm_string_length
+             */
+            void add_role(osmium::RelationMember& member, const char* role, const size_t length) {
+                if (length > osmium::max_osm_string_length) {
+                    throw std::length_error("OSM relation member role is too long");
+                }
+                member.set_role_size(osmium::string_size_type(length) + 1);
+                add_size(append(role, osmium::memory::item_size_type(length)) + append_zero());
+                add_padding(true);
+            }
+
+        public:
+
+            explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
+                ObjectBuilder<RelationMemberList>(buffer, parent) {
+            }
+
+            ~RelationMemberListBuilder() {
+                add_padding();
+            }
+
+            /**
+             * Add a member to the relation.
+             *
+             * @param type The type (node, way, or relation).
+             * @param ref The ID of the member.
+             * @param role The role of the member.
+             * @param role_length Length of the role (without \0 termination).
+             * @param full_member Optional pointer to the member object. If it
+             *                    is available a copy will be added to the
+             *                    relation.
+             * @throws std:length_error If role_length is greater than
+             *         osmium::max_osm_string_length
+             */
+            void add_member(osmium::item_type type, object_id_type ref, const char* role, const size_t role_length, const osmium::OSMObject* full_member = nullptr) {
+                osmium::RelationMember* member = reserve_space_for<osmium::RelationMember>();
+                new (member) osmium::RelationMember(ref, type, full_member != nullptr);
+                add_size(sizeof(RelationMember));
+                add_role(*member, role, role_length);
+                if (full_member) {
+                    add_item(full_member);
+                }
+            }
+
+            /**
+             * Add a member to the relation.
+             *
+             * @param type The type (node, way, or relation).
+             * @param ref The ID of the member.
+             * @param role The role of the member (\0 terminated string).
+             * @param full_member Optional pointer to the member object. If it
+             *                    is available a copy will be added to the
+             *                    relation.
+             * @throws std:length_error If role is longer than osmium::max_osm_string_length
+             */
+            void add_member(osmium::item_type type, object_id_type ref, const char* role, const osmium::OSMObject* full_member = nullptr) {
+                add_member(type, ref, role, std::strlen(role), full_member);
+            }
+
+            /**
+             * Add a member to the relation.
+             *
+             * @param type The type (node, way, or relation).
+             * @param ref The ID of the member.
+             * @param role The role of the member.
+             * @param full_member Optional pointer to the member object. If it
+             *                    is available a copy will be added to the
+             *                    relation.
+             * @throws std:length_error If role is longer than osmium::max_osm_string_length
+             */
+            void add_member(osmium::item_type type, object_id_type ref, const std::string& role, const osmium::OSMObject* full_member = nullptr) {
+                add_member(type, ref, role.data(), role.size(), full_member);
+            }
+
+        }; // class RelationMemberListBuilder
+
+        class ChangesetDiscussionBuilder : public ObjectBuilder<ChangesetDiscussion> {
+
+            osmium::ChangesetComment* m_comment = nullptr;
+
+            void add_user(osmium::ChangesetComment& comment, const char* user, const size_t length) {
+                if (length > osmium::max_osm_string_length) {
+                    throw std::length_error("OSM user name is too long");
+                }
+                comment.set_user_size(osmium::string_size_type(length) + 1);
+                add_size(append(user, osmium::memory::item_size_type(length)) + append_zero());
+            }
+
+            void add_text(osmium::ChangesetComment& comment, const char* text, const size_t length) {
+                // XXX There is no limit on the length of a comment text. We
+                // limit it here to 2^16-2 characters, because that's all that
+                // will fit into our internal data structure. This is not ideal,
+                // and will have to be discussed and cleared up.
+                if (length > std::numeric_limits<osmium::string_size_type>::max() - 1) {
+                    throw std::length_error("OSM changeset comment is too long");
+                }
+                comment.set_text_size(osmium::string_size_type(length) + 1);
+                add_size(append(text, osmium::memory::item_size_type(length)) + append_zero());
+                add_padding(true);
+            }
+
+        public:
+
+            explicit ChangesetDiscussionBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
+                ObjectBuilder<ChangesetDiscussion>(buffer, parent) {
+            }
+
+            ~ChangesetDiscussionBuilder() {
+                assert(!m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!");
+                add_padding();
+            }
+
+            void add_comment(osmium::Timestamp date, osmium::user_id_type uid, const char* user) {
+                assert(!m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!");
+                m_comment = reserve_space_for<osmium::ChangesetComment>();
+                new (m_comment) osmium::ChangesetComment(date, uid);
+                add_size(sizeof(ChangesetComment));
+                add_user(*m_comment, user, std::strlen(user));
+            }
+
+            void add_comment_text(const char* text) {
+                assert(m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!");
+                add_text(*m_comment, text, std::strlen(text));
+                m_comment = nullptr;
+            }
+
+            void add_comment_text(const std::string& text) {
+                assert(m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!");
+                add_text(*m_comment, text.c_str(), text.size());
+                m_comment = nullptr;
+            }
+
+        }; // class ChangesetDiscussionBuilder
+
+        template <typename T>
+        class OSMObjectBuilder : public ObjectBuilder<T> {
+
+        public:
+
+            explicit OSMObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
+                ObjectBuilder<T>(buffer, parent) {
+                static_cast<Builder*>(this)->reserve_space_for<string_size_type>();
+                static_cast<Builder*>(this)->add_size(sizeof(string_size_type));
+            }
+
+            void add_tags(const std::initializer_list<std::pair<const char*, const char*>>& tags) {
+                osmium::builder::TagListBuilder tl_builder(static_cast<Builder*>(this)->buffer(), this);
+                for (const auto& p : tags) {
+                    tl_builder.add_tag(p.first, p.second);
+                }
+            }
+
+        }; // class OSMObjectBuilder
+
+        typedef OSMObjectBuilder<osmium::Node> NodeBuilder;
+        typedef OSMObjectBuilder<osmium::Relation> RelationBuilder;
+
+        class WayBuilder : public OSMObjectBuilder<osmium::Way> {
+
+        public:
+
+            explicit WayBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
+                OSMObjectBuilder<osmium::Way>(buffer, parent) {
+            }
+
+            void add_node_refs(const std::initializer_list<osmium::NodeRef>& nodes) {
+                osmium::builder::WayNodeListBuilder builder(buffer(), this);
+                for (const auto& node_ref : nodes) {
+                    builder.add_node_ref(node_ref);
+                }
+            }
+
+        }; // class WayBuilder
+
+        class AreaBuilder : public OSMObjectBuilder<osmium::Area> {
+
+        public:
+
+            explicit AreaBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
+                OSMObjectBuilder<osmium::Area>(buffer, parent) {
+            }
+
+            /**
+             * Initialize area attributes from the attributes of the given object.
+             */
+            void initialize_from_object(const osmium::OSMObject& source) {
+                osmium::Area& area = object();
+                area.set_id(osmium::object_id_to_area_id(source.id(), source.type()));
+                area.set_version(source.version());
+                area.set_changeset(source.changeset());
+                area.set_timestamp(source.timestamp());
+                area.set_visible(source.visible());
+                area.set_uid(source.uid());
+
+                add_user(source.user());
+            }
+
+        }; // class AreaBuilder
+
+        typedef ObjectBuilder<osmium::Changeset> ChangesetBuilder;
+
+    } // namespace builder
+
+} // namespace osmium
+
+#endif // OSMIUM_BUILDER_OSM_OBJECT_BUILDER_HPP
diff --git a/contrib/libosmium/osmium/diff_handler.hpp b/contrib/libosmium/osmium/diff_handler.hpp
new file mode 100644
index 0000000..4f9b3a1
--- /dev/null
+++ b/contrib/libosmium/osmium/diff_handler.hpp
@@ -0,0 +1,67 @@
+#ifndef OSMIUM_DIFF_HANDLER_HPP
+#define OSMIUM_DIFF_HANDLER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/osm/diff_object.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Osmium diff handlers provide access to differences between OSM object versions
+     */
+    namespace diff_handler {
+
+        class DiffHandler {
+
+        public:
+
+            DiffHandler() {
+            }
+
+            void node(const osmium::DiffNode&) const {
+            }
+
+            void way(const osmium::DiffWay&) const {
+            }
+
+            void relation(const osmium::DiffRelation&) const {
+            }
+
+        }; // class DiffHandler
+
+    } // namespace diff_handler
+
+} // namespace osmium
+
+#endif // OSMIUM_DIFF_HANDLER_HPP
diff --git a/contrib/libosmium/osmium/diff_iterator.hpp b/contrib/libosmium/osmium/diff_iterator.hpp
new file mode 100644
index 0000000..4ee67f7
--- /dev/null
+++ b/contrib/libosmium/osmium/diff_iterator.hpp
@@ -0,0 +1,129 @@
+#ifndef OSMIUM_DIFF_ITERATOR_HPP
+#define OSMIUM_DIFF_ITERATOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <iterator>
+#include <type_traits>
+
+#include <osmium/osm/diff_object.hpp>
+
+namespace osmium {
+
+    class OSMObject;
+
+    template <typename TBasicIterator>
+    class DiffIterator : public std::iterator<std::input_iterator_tag, const osmium::DiffObject> {
+
+        static_assert(std::is_base_of<osmium::OSMObject, typename TBasicIterator::value_type>::value, "TBasicIterator::value_type must derive from osmium::OSMObject");
+
+        TBasicIterator m_prev;
+        TBasicIterator m_curr;
+        TBasicIterator m_next;
+
+        const TBasicIterator m_end;
+
+        mutable osmium::DiffObject m_diff;
+
+        void set_diff() const {
+            assert(m_curr != m_end);
+
+            TBasicIterator prev = m_prev;
+            if (prev->type() != m_curr->type() || prev->id() != m_curr->id()) {
+                prev = m_curr;
+            }
+
+            TBasicIterator next = m_next;
+            if (next == m_end || next->type() != m_curr->type() || next->id() != m_curr->id()) {
+                next = m_curr;
+            }
+
+            m_diff = osmium::DiffObject(*prev, *m_curr, *next);
+        }
+
+    public:
+
+        explicit DiffIterator(TBasicIterator begin, TBasicIterator end) :
+            m_prev(begin),
+            m_curr(begin),
+            m_next(begin == end ? begin : ++begin),
+            m_end(end) {
+        }
+
+        DiffIterator(const DiffIterator&) = default;
+        DiffIterator& operator=(const DiffIterator&) = default;
+
+        DiffIterator(DiffIterator&&) = default;
+        DiffIterator& operator=(DiffIterator&&) = default;
+
+        DiffIterator& operator++() {
+            m_prev = std::move(m_curr);
+            m_curr = m_next;
+
+            if (m_next != m_end) {
+                ++m_next;
+            }
+
+            return *this;
+        }
+
+        DiffIterator operator++(int) {
+            DiffIterator tmp(*this);
+            operator++();
+            return tmp;
+        }
+
+        bool operator==(const DiffIterator& rhs) const {
+            return m_curr == rhs.m_curr && m_end == rhs.m_end;
+        }
+
+        bool operator!=(const DiffIterator& rhs) const {
+            return !(*this == rhs);
+        }
+
+        reference operator*() const {
+            set_diff();
+            return m_diff;
+        }
+
+        pointer operator->() const {
+            set_diff();
+            return &m_diff;
+        }
+
+    }; // class DiffIterator
+
+} // namespace osmium
+
+#endif // OSMIUM_DIFF_ITERATOR_HPP
diff --git a/contrib/libosmium/osmium/diff_visitor.hpp b/contrib/libosmium/osmium/diff_visitor.hpp
new file mode 100644
index 0000000..e7dc576
--- /dev/null
+++ b/contrib/libosmium/osmium/diff_visitor.hpp
@@ -0,0 +1,104 @@
+#ifndef OSMIUM_DIFF_VISITOR_HPP
+#define OSMIUM_DIFF_VISITOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/diff_iterator.hpp>
+#include <osmium/io/input_iterator.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/diff_object.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+    namespace detail {
+
+        template <typename THandler>
+        inline void apply_diff_iterator_recurse(const osmium::DiffObject& diff, THandler& handler) {
+            switch (diff.type()) {
+                case osmium::item_type::node:
+                    handler.node(static_cast<const osmium::DiffNode&>(diff));
+                    break;
+                case osmium::item_type::way:
+                    handler.way(static_cast<const osmium::DiffWay&>(diff));
+                    break;
+                case osmium::item_type::relation:
+                    handler.relation(static_cast<const osmium::DiffRelation&>(diff));
+                    break;
+                default:
+                    throw osmium::unknown_type();
+            }
+        }
+
+        template <typename THandler, typename... TRest>
+        inline void apply_diff_iterator_recurse(const osmium::DiffObject& diff, THandler& handler, TRest&... more) {
+            apply_diff_iterator_recurse(diff, handler);
+            apply_diff_iterator_recurse(diff, more...);
+        }
+
+    } // namespace detail
+
+    template <typename TIterator, typename... THandlers>
+    inline void apply_diff(TIterator it, TIterator end, THandlers&... handlers) {
+        typedef osmium::DiffIterator<TIterator> diff_iterator;
+
+        diff_iterator dit(it, end);
+        diff_iterator dend(end, end);
+
+        for (; dit != dend; ++dit) {
+            detail::apply_diff_iterator_recurse(*dit, handlers...);
+        }
+    }
+
+    class OSMObject;
+
+    template <typename TSource, typename... THandlers>
+    inline void apply_diff(TSource& source, THandlers&... handlers) {
+        apply_diff(osmium::io::InputIterator<TSource, osmium::OSMObject> {source},
+                   osmium::io::InputIterator<TSource, osmium::OSMObject> {},
+                   handlers...);
+    }
+
+    template <typename... THandlers>
+    inline void apply_diff(osmium::memory::Buffer& buffer, THandlers&... handlers) {
+        apply_diff(buffer.begin(), buffer.end(), handlers...);
+    }
+
+    template <typename... THandlers>
+    inline void apply_diff(const osmium::memory::Buffer& buffer, THandlers&... handlers) {
+        apply_diff(buffer.cbegin(), buffer.cend(), handlers...);
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_DIFF_VISITOR_HPP
diff --git a/contrib/libosmium/osmium/dynamic_handler.hpp b/contrib/libosmium/osmium/dynamic_handler.hpp
new file mode 100644
index 0000000..39baba5
--- /dev/null
+++ b/contrib/libosmium/osmium/dynamic_handler.hpp
@@ -0,0 +1,190 @@
+#ifndef OSMIUM_DYNAMIC_HANDLER_HPP
+#define OSMIUM_DYNAMIC_HANDLER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <memory>
+#include <utility>
+
+#include <osmium/fwd.hpp>
+#include <osmium/handler.hpp>
+
+namespace osmium {
+
+    namespace handler {
+
+        namespace detail {
+
+            class HandlerWrapperBase {
+
+            public:
+
+                virtual ~HandlerWrapperBase() {
+                }
+
+                virtual void node(const osmium::Node&) {
+                }
+
+                virtual void way(const osmium::Way&) {
+                }
+
+                virtual void relation(const osmium::Relation&) {
+                }
+
+                virtual void area(const osmium::Area&) {
+                }
+
+                virtual void changeset(const osmium::Changeset&) {
+                }
+
+                virtual void flush() {
+                }
+
+            }; // class HandlerWrapperBase
+
+
+            // The following uses trick from
+            // http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence
+            // to either call handler style functions or visitor style operator().
+
+#define OSMIUM_DYNAMIC_HANDLER_DISPATCH(_name_, _type_) \
+template <typename THandler> \
+auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, int) -> decltype(handler._name_(object), void()) { \
+    handler._name_(object); \
+} \
+template <typename THandler> \
+auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) -> decltype(handler(object), void()) { \
+    handler(object); \
+}
+
+            OSMIUM_DYNAMIC_HANDLER_DISPATCH(node, Node)
+            OSMIUM_DYNAMIC_HANDLER_DISPATCH(way, Way)
+            OSMIUM_DYNAMIC_HANDLER_DISPATCH(relation, Relation)
+            OSMIUM_DYNAMIC_HANDLER_DISPATCH(changeset, Changeset)
+            OSMIUM_DYNAMIC_HANDLER_DISPATCH(area, Area)
+
+            template <typename THandler>
+            auto flush_dispatch(THandler& handler, int) -> decltype(handler.flush(), void()) {
+                handler.flush();
+            }
+
+            template <typename THandler>
+            void flush_dispatch(THandler&, long) {}
+
+            template <typename THandler>
+            class HandlerWrapper : public HandlerWrapperBase {
+
+                THandler m_handler;
+
+            public:
+
+                template <typename... TArgs>
+                HandlerWrapper(TArgs&&... args) :
+                    m_handler(std::forward<TArgs>(args)...) {
+                }
+
+                void node(const osmium::Node& node) override final {
+                    node_dispatch(m_handler, node, 0);
+                }
+
+                void way(const osmium::Way& way) override final {
+                    way_dispatch(m_handler, way, 0);
+                }
+
+                void relation(const osmium::Relation& relation) override final {
+                    relation_dispatch(m_handler, relation, 0);
+                }
+
+                void area(const osmium::Area& area) override final {
+                    area_dispatch(m_handler, area, 0);
+                }
+
+                void changeset(const osmium::Changeset& changeset) override final {
+                    changeset_dispatch(m_handler, changeset, 0);
+                }
+
+                void flush() override final {
+                    flush_dispatch(m_handler, 0);
+                }
+
+            }; // class HandlerWrapper
+
+        } // namespace detail
+
+        class DynamicHandler : public osmium::handler::Handler {
+
+            typedef std::unique_ptr<osmium::handler::detail::HandlerWrapperBase> impl_ptr;
+            impl_ptr m_impl;
+
+        public:
+
+            DynamicHandler() :
+                m_impl(impl_ptr(new osmium::handler::detail::HandlerWrapperBase)) {
+            }
+
+            template <typename THandler, typename... TArgs>
+            void set(TArgs&&... args) {
+                m_impl = impl_ptr(new osmium::handler::detail::HandlerWrapper<THandler>(std::forward<TArgs>(args)...));
+            }
+
+            void node(const osmium::Node& node) {
+                m_impl->node(node);
+            }
+
+            void way(const osmium::Way& way) {
+                m_impl->way(way);
+            }
+
+            void relation(const osmium::Relation& relation) {
+                m_impl->relation(relation);
+            }
+
+            void area(const osmium::Area& area) {
+                m_impl->area(area);
+            }
+
+            void changeset(const osmium::Changeset& changeset) {
+                m_impl->changeset(changeset);
+            }
+
+            void flush() {
+                m_impl->flush();
+            }
+
+        }; // class DynamicHandler
+
+    } // namspace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_DYNAMIC_HANDLER_HPP
diff --git a/contrib/libosmium/osmium/experimental/flex_reader.hpp b/contrib/libosmium/osmium/experimental/flex_reader.hpp
new file mode 100644
index 0000000..c1d2357
--- /dev/null
+++ b/contrib/libosmium/osmium/experimental/flex_reader.hpp
@@ -0,0 +1,137 @@
+#ifndef OSMIUM_EXPERIMENTAL_FLEX_READER_HPP
+#define OSMIUM_EXPERIMENTAL_FLEX_READER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <string>
+#include <vector>
+
+#include <osmium/area/assembler.hpp>
+#include <osmium/area/multipolygon_collector.hpp>
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/io/reader.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Experimental code that is not "officially" supported.
+     */
+    namespace experimental {
+
+        template <typename TLocationHandler>
+        class FlexReader {
+
+            bool m_with_areas;
+            osmium::osm_entity_bits::type m_entities;
+
+            TLocationHandler& m_location_handler;
+
+            osmium::io::Reader m_reader;
+            osmium::area::Assembler::config_type m_assembler_config;
+            osmium::area::MultipolygonCollector<osmium::area::Assembler> m_collector;
+
+        public:
+
+            explicit FlexReader(const osmium::io::File& file, TLocationHandler& location_handler, osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::nwr) :
+                m_with_areas((entities & osmium::osm_entity_bits::area) != 0),
+                m_entities((entities & ~osmium::osm_entity_bits::area) | (m_with_areas ? osmium::osm_entity_bits::node | osmium::osm_entity_bits::way : osmium::osm_entity_bits::nothing)),
+                m_location_handler(location_handler),
+                m_reader(file, m_entities),
+                m_assembler_config(),
+                m_collector(m_assembler_config)
+            {
+                m_location_handler.ignore_errors();
+                if (m_with_areas) {
+                    osmium::io::Reader reader(file, osmium::osm_entity_bits::relation);
+                    m_collector.read_relations(reader);
+                    reader.close();
+                }
+            }
+
+            explicit FlexReader(const std::string& filename, TLocationHandler& location_handler, osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::nwr) :
+                FlexReader(osmium::io::File(filename), location_handler, entities) {
+            }
+
+            explicit FlexReader(const char* filename, TLocationHandler& location_handler, osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::nwr) :
+                FlexReader(osmium::io::File(filename), location_handler, entities) {
+            }
+
+            osmium::memory::Buffer read() {
+                osmium::memory::Buffer buffer = m_reader.read();
+
+                if (buffer) {
+                    if (m_with_areas) {
+                        std::vector<osmium::memory::Buffer> area_buffers;
+                        osmium::apply(buffer, m_location_handler, m_collector.handler([&area_buffers](osmium::memory::Buffer&& area_buffer) {
+                            area_buffers.push_back(std::move(area_buffer));
+                        }));
+                        for (const osmium::memory::Buffer& b : area_buffers) {
+                            buffer.add_buffer(b);
+                            buffer.commit();
+                        }
+                    } else if (m_entities & (osmium::osm_entity_bits::node | osmium::osm_entity_bits::way)) {
+                        osmium::apply(buffer, m_location_handler);
+                    }
+                }
+
+                return buffer;
+            }
+
+            osmium::io::Header header() {
+                return m_reader.header();
+            }
+
+            void close() {
+                return m_reader.close();
+            }
+
+            bool eof() const {
+                return m_reader.eof();
+            }
+
+            const osmium::area::MultipolygonCollector<osmium::area::Assembler>& collector() const {
+                return m_collector;
+            }
+
+        }; // class FlexReader
+
+    } // namespace experimental
+
+} // namespace osmium
+
+#endif // OSMIUM_EXPERIMENTAL_FLEX_READER_HPP
diff --git a/contrib/libosmium/osmium/fwd.hpp b/contrib/libosmium/osmium/fwd.hpp
new file mode 100644
index 0000000..bfcb5f5
--- /dev/null
+++ b/contrib/libosmium/osmium/fwd.hpp
@@ -0,0 +1,70 @@
+#ifndef OSMIUM_FWD_HPP
+#define OSMIUM_FWD_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ *
+ * @file
+ *
+ * This file contains forward declarations for commonly used Osmium classes.
+ *
+ */
+
+namespace osmium {
+
+    class Area;
+    class Box;
+    class Changeset;
+    class ChangesetComment;
+    class ChangesetDiscussion;
+    class InnerRing;
+    class Location;
+    class Node;
+    class NodeRef;
+    class NodeRefList;
+    class OSMEntity;
+    class OSMObject;
+    class OuterRing;
+    class Relation;
+    class RelationMemberList;
+    class Segment;
+    class Tag;
+    class TagList;
+    class Timestamp;
+    class Way;
+    class WayNodeList;
+
+} // namespace osmium
+
+#endif // OSMIUM_FWD_HPP
diff --git a/contrib/libosmium/osmium/geom/coordinates.hpp b/contrib/libosmium/osmium/geom/coordinates.hpp
new file mode 100644
index 0000000..6544e68
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/coordinates.hpp
@@ -0,0 +1,96 @@
+#ifndef OSMIUM_GEOM_COORDINATES_HPP
+#define OSMIUM_GEOM_COORDINATES_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iosfwd>
+#include <string>
+
+#include <osmium/osm/location.hpp>
+#include <osmium/util/double.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        struct Coordinates {
+
+            double x;
+            double y;
+
+            explicit Coordinates(double cx, double cy) noexcept : x(cx), y(cy) {
+            }
+
+            Coordinates(const osmium::Location& location) : x(location.lon()), y(location.lat()) {
+            }
+
+            void append_to_string(std::string& s, const char infix, int precision) const {
+                osmium::util::double2string(s, x, precision);
+                s += infix;
+                osmium::util::double2string(s, y, precision);
+            }
+
+            void append_to_string(std::string& s, const char prefix, const char infix, const char suffix, int precision) const {
+                s += prefix;
+                append_to_string(s, infix, precision);
+                s += suffix;
+            }
+
+        }; // struct coordinates
+
+        /**
+         * Compare whether two Coordinates are identical. Might not give the
+         * right result if the coordinates have been the result of some
+         * calculation that introduced rounding errors.
+         */
+        inline bool operator==(const Coordinates& lhs, const Coordinates& rhs) noexcept {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+            return lhs.x == rhs.x && lhs.y == rhs.y;
+#pragma GCC diagnostic pop
+        }
+
+        inline bool operator!=(const Coordinates& lhs, const Coordinates& rhs) noexcept {
+            return ! operator==(lhs, rhs);
+        }
+
+        template <typename TChar, typename TTraits>
+        inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const Coordinates& c) {
+            return out << '(' << c.x << ',' << c.y << ')';
+        }
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_COORDINATES_HPP
diff --git a/contrib/libosmium/osmium/geom/factory.hpp b/contrib/libosmium/osmium/geom/factory.hpp
new file mode 100644
index 0000000..49dc78c
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/factory.hpp
@@ -0,0 +1,419 @@
+#ifndef OSMIUM_GEOM_FACTORY_HPP
+#define OSMIUM_GEOM_FACTORY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/area.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when an invalid geometry is encountered. An example
+     * would be a linestring with less than two points.
+     */
+    class geometry_error : public std::runtime_error {
+
+        std::string m_message;
+        osmium::object_id_type m_id;
+
+    public:
+
+        geometry_error(const std::string& message, const char* object_type = "", osmium::object_id_type id = 0) :
+            std::runtime_error(message),
+            m_message(message),
+            m_id(id) {
+            if (m_id != 0) {
+                m_message += " (";
+                m_message += object_type;
+                m_message += "_id=";
+                m_message += std::to_string(m_id);
+                m_message += ")";
+            }
+        }
+
+        void set_id(const char* object_type, osmium::object_id_type id) {
+            if (m_id == 0 && id != 0) {
+                m_message += " (";
+                m_message += object_type;
+                m_message += "_id=";
+                m_message += std::to_string(id);
+                m_message += ")";
+            }
+            m_id = id;
+        }
+
+        osmium::object_id_type id() const noexcept {
+            return m_id;
+        }
+
+        virtual const char* what() const noexcept override {
+            return m_message.c_str();
+        }
+
+    }; // struct geometry_error
+
+    /**
+     * @brief Everything related to geometry handling.
+     */
+    namespace geom {
+
+        /**
+         * Which nodes of a way to use for a linestring.
+         */
+        enum class use_nodes : bool {
+            unique = true, ///< Remove consecutive nodes with same location.
+            all    = false ///< Use all nodes.
+        }; // enum class use_nodes
+
+        /**
+         * Which direction the linestring created from a way
+         * should have.
+         */
+        enum class direction : bool {
+            backward = true, ///< Linestring has reverse direction.
+            forward  = false ///< Linestring has same direction as way.
+        }; // enum class direction
+
+        /**
+         * This pseudo projection just returns its WGS84 input unchanged.
+         * Used as a template parameter if a real projection is not needed.
+         */
+        class IdentityProjection {
+
+        public:
+
+            Coordinates operator()(osmium::Location location) const {
+                return Coordinates{location.lon(), location.lat()};
+            }
+
+            int epsg() const noexcept {
+                return 4326;
+            }
+
+            std::string proj_string() const {
+                return "+proj=longlat +datum=WGS84 +no_defs";
+            }
+
+        }; // class IdentityProjection
+
+        /**
+         * Geometry factory.
+         */
+        template <typename TGeomImpl, typename TProjection = IdentityProjection>
+        class GeometryFactory {
+
+            /**
+             * Add all points of an outer or inner ring to a multipolygon.
+             */
+            void add_points(const osmium::OuterRing& nodes) {
+                osmium::Location last_location;
+                for (const osmium::NodeRef& node_ref : nodes) {
+                    if (last_location != node_ref.location()) {
+                        last_location = node_ref.location();
+                        m_impl.multipolygon_add_location(m_projection(last_location));
+                    }
+                }
+            }
+
+            TProjection m_projection;
+            TGeomImpl m_impl;
+
+        public:
+
+            /**
+             * Constructor for default initialized projection.
+             */
+            template <typename... TArgs>
+            GeometryFactory<TGeomImpl, TProjection>(TArgs&&... args) :
+                m_projection(),
+                m_impl(std::forward<TArgs>(args)...) {
+            }
+
+            /**
+             * Constructor for explicitly initialized projection. Note that the
+             * projection is moved into the GeometryFactory.
+             */
+            template <typename... TArgs>
+            GeometryFactory<TGeomImpl, TProjection>(TProjection&& projection, TArgs&&... args) :
+                m_projection(std::move(projection)),
+                m_impl(std::forward<TArgs>(args)...) {
+            }
+
+            typedef TProjection projection_type;
+            typedef typename TGeomImpl::point_type        point_type;
+            typedef typename TGeomImpl::linestring_type   linestring_type;
+            typedef typename TGeomImpl::polygon_type      polygon_type;
+            typedef typename TGeomImpl::multipolygon_type multipolygon_type;
+            typedef typename TGeomImpl::ring_type         ring_type;
+
+            int epsg() const {
+                return m_projection.epsg();
+            }
+
+            std::string proj_string() const {
+                return m_projection.proj_string();
+            }
+
+            /* Point */
+
+            point_type create_point(const osmium::Location& location) const {
+                return m_impl.make_point(m_projection(location));
+            }
+
+            point_type create_point(const osmium::Node& node) {
+                try {
+                    return create_point(node.location());
+                } catch (osmium::geometry_error& e) {
+                    e.set_id("node", node.id());
+                    throw;
+                }
+            }
+
+            point_type create_point(const osmium::NodeRef& node_ref) {
+                try {
+                    return create_point(node_ref.location());
+                } catch (osmium::geometry_error& e) {
+                    e.set_id("node", node_ref.ref());
+                    throw;
+                }
+            }
+
+            /* LineString */
+
+            void linestring_start() {
+                m_impl.linestring_start();
+            }
+
+            template <typename TIter>
+            size_t fill_linestring(TIter it, TIter end) {
+                size_t num_points = 0;
+                for (; it != end; ++it, ++num_points) {
+                    m_impl.linestring_add_location(m_projection(it->location()));
+                }
+                return num_points;
+            }
+
+            template <typename TIter>
+            size_t fill_linestring_unique(TIter it, TIter end) {
+                size_t num_points = 0;
+                osmium::Location last_location;
+                for (; it != end; ++it) {
+                    if (last_location != it->location()) {
+                        last_location = it->location();
+                        m_impl.linestring_add_location(m_projection(last_location));
+                        ++num_points;
+                    }
+                }
+                return num_points;
+            }
+
+            linestring_type linestring_finish(size_t num_points) {
+                return m_impl.linestring_finish(num_points);
+            }
+
+            linestring_type create_linestring(const osmium::WayNodeList& wnl, use_nodes un = use_nodes::unique, direction dir = direction::forward) {
+                linestring_start();
+                size_t num_points = 0;
+
+                if (un == use_nodes::unique) {
+                    osmium::Location last_location;
+                    switch (dir) {
+                        case direction::forward:
+                            num_points = fill_linestring_unique(wnl.cbegin(), wnl.cend());
+                            break;
+                        case direction::backward:
+                            num_points = fill_linestring_unique(wnl.crbegin(), wnl.crend());
+                            break;
+                    }
+                } else {
+                    switch (dir) {
+                        case direction::forward:
+                            num_points = fill_linestring(wnl.cbegin(), wnl.cend());
+                            break;
+                        case direction::backward:
+                            num_points = fill_linestring(wnl.crbegin(), wnl.crend());
+                            break;
+                    }
+                }
+
+                if (num_points < 2) {
+                    throw osmium::geometry_error("need at least two points for linestring");
+                }
+
+                return linestring_finish(num_points);
+            }
+
+            linestring_type create_linestring(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
+                try {
+                    return create_linestring(way.nodes(), un, dir);
+                } catch (osmium::geometry_error& e) {
+                    e.set_id("way", way.id());
+                    throw;
+                }
+            }
+
+            /* Polygon */
+
+            void polygon_start() {
+                m_impl.polygon_start();
+            }
+
+            template <typename TIter>
+            size_t fill_polygon(TIter it, TIter end) {
+                size_t num_points = 0;
+                for (; it != end; ++it, ++num_points) {
+                    m_impl.polygon_add_location(m_projection(it->location()));
+                }
+                return num_points;
+            }
+
+            template <typename TIter>
+            size_t fill_polygon_unique(TIter it, TIter end) {
+                size_t num_points = 0;
+                osmium::Location last_location;
+                for (; it != end; ++it) {
+                    if (last_location != it->location()) {
+                        last_location = it->location();
+                        m_impl.polygon_add_location(m_projection(last_location));
+                        ++num_points;
+                    }
+                }
+                return num_points;
+            }
+
+            polygon_type polygon_finish(size_t num_points) {
+                return m_impl.polygon_finish(num_points);
+            }
+
+            polygon_type create_polygon(const osmium::WayNodeList& wnl, use_nodes un = use_nodes::unique, direction dir = direction::forward) {
+                polygon_start();
+                size_t num_points = 0;
+
+                if (un == use_nodes::unique) {
+                    osmium::Location last_location;
+                    switch (dir) {
+                        case direction::forward:
+                            num_points = fill_polygon_unique(wnl.cbegin(), wnl.cend());
+                            break;
+                        case direction::backward:
+                            num_points = fill_polygon_unique(wnl.crbegin(), wnl.crend());
+                            break;
+                    }
+                } else {
+                    switch (dir) {
+                        case direction::forward:
+                            num_points = fill_polygon(wnl.cbegin(), wnl.cend());
+                            break;
+                        case direction::backward:
+                            num_points = fill_polygon(wnl.crbegin(), wnl.crend());
+                            break;
+                    }
+                }
+
+                if (num_points < 4) {
+                    throw osmium::geometry_error("need at least four points for polygon");
+                }
+
+                return polygon_finish(num_points);
+            }
+
+            polygon_type create_polygon(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
+                try {
+                    return create_polygon(way.nodes(), un, dir);
+                } catch (osmium::geometry_error& e) {
+                    e.set_id("way", way.id());
+                    throw;
+                }
+            }
+
+            /* MultiPolygon */
+
+            multipolygon_type create_multipolygon(const osmium::Area& area) {
+                try {
+                    size_t num_polygons = 0;
+                    size_t num_rings = 0;
+                    m_impl.multipolygon_start();
+
+                    for (auto it = area.cbegin(); it != area.cend(); ++it) {
+                        const osmium::OuterRing& ring = static_cast<const osmium::OuterRing&>(*it);
+                        if (it->type() == osmium::item_type::outer_ring) {
+                            if (num_polygons > 0) {
+                                m_impl.multipolygon_polygon_finish();
+                            }
+                            m_impl.multipolygon_polygon_start();
+                            m_impl.multipolygon_outer_ring_start();
+                            add_points(ring);
+                            m_impl.multipolygon_outer_ring_finish();
+                            ++num_rings;
+                            ++num_polygons;
+                        } else if (it->type() == osmium::item_type::inner_ring) {
+                            m_impl.multipolygon_inner_ring_start();
+                            add_points(ring);
+                            m_impl.multipolygon_inner_ring_finish();
+                            ++num_rings;
+                        }
+                    }
+
+                    // if there are no rings, this area is invalid
+                    if (num_rings == 0) {
+                        throw osmium::geometry_error("area contains no rings");
+                    }
+
+                    m_impl.multipolygon_polygon_finish();
+                    return m_impl.multipolygon_finish();
+                } catch (osmium::geometry_error& e) {
+                    e.set_id("area", area.id());
+                    throw;
+                }
+            }
+
+        }; // class GeometryFactory
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_FACTORY_HPP
diff --git a/contrib/libosmium/osmium/geom/geojson.hpp b/contrib/libosmium/osmium/geom/geojson.hpp
new file mode 100644
index 0000000..e5b5a9c
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/geojson.hpp
@@ -0,0 +1,160 @@
+#ifndef OSMIUM_GEOM_GEOJSON_HPP
+#define OSMIUM_GEOM_GEOJSON_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <string>
+#include <utility>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/factory.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        namespace detail {
+
+            class GeoJSONFactoryImpl {
+
+                std::string m_str;
+                int m_precision;
+
+            public:
+
+                typedef std::string point_type;
+                typedef std::string linestring_type;
+                typedef std::string polygon_type;
+                typedef std::string multipolygon_type;
+                typedef std::string ring_type;
+
+                GeoJSONFactoryImpl(int precision = 7) :
+                    m_precision(precision) {
+                }
+
+                /* Point */
+
+                // { "type": "Point", "coordinates": [100.0, 0.0] }
+                point_type make_point(const osmium::geom::Coordinates& xy) const {
+                    std::string str {"{\"type\":\"Point\",\"coordinates\":"};
+                    xy.append_to_string(str, '[', ',', ']', m_precision);
+                    str += "}";
+                    return str;
+                }
+
+                /* LineString */
+
+                // { "type": "LineString", "coordinates": [ [100.0, 0.0], [101.0, 1.0] ] }
+                void linestring_start() {
+                    m_str = "{\"type\":\"LineString\",\"coordinates\":[";
+                }
+
+                void linestring_add_location(const osmium::geom::Coordinates& xy) {
+                    xy.append_to_string(m_str, '[', ',', ']', m_precision);
+                    m_str += ',';
+                }
+
+                linestring_type linestring_finish(size_t /* num_points */) {
+                    assert(!m_str.empty());
+                    std::string str;
+
+                    using std::swap;
+                    swap(str, m_str);
+
+                    str.back() = ']';
+                    str += "}";
+                    return str;
+                }
+
+                /* MultiPolygon */
+
+                void multipolygon_start() {
+                    m_str = "{\"type\":\"MultiPolygon\",\"coordinates\":[";
+                }
+
+                void multipolygon_polygon_start() {
+                    m_str += '[';
+                }
+
+                void multipolygon_polygon_finish() {
+                    m_str += "],";
+                }
+
+                void multipolygon_outer_ring_start() {
+                    m_str += '[';
+                }
+
+                void multipolygon_outer_ring_finish() {
+                    assert(!m_str.empty());
+                    m_str.back() = ']';
+                }
+
+                void multipolygon_inner_ring_start() {
+                    m_str += ",[";
+                }
+
+                void multipolygon_inner_ring_finish() {
+                    assert(!m_str.empty());
+                    m_str.back() = ']';
+                }
+
+                void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+                    xy.append_to_string(m_str, '[', ',', ']', m_precision);
+                    m_str += ',';
+                }
+
+                multipolygon_type multipolygon_finish() {
+                    assert(!m_str.empty());
+                    std::string str;
+
+                    using std::swap;
+                    swap(str, m_str);
+
+                    str.back() = ']';
+                    str += "}";
+                    return str;
+                }
+
+            }; // class GeoJSONFactoryImpl
+
+        } // namespace detail
+
+        template <typename TProjection = IdentityProjection>
+        using GeoJSONFactory = GeometryFactory<osmium::geom::detail::GeoJSONFactoryImpl, TProjection>;
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_GEOJSON_HPP
diff --git a/contrib/libosmium/osmium/geom/geos.hpp b/contrib/libosmium/osmium/geom/geos.hpp
new file mode 100644
index 0000000..49b1fd7
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/geos.hpp
@@ -0,0 +1,240 @@
+#ifndef OSMIUM_GEOM_GEOS_HPP
+#define OSMIUM_GEOM_GEOS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * This file contains code for conversion of OSM geometries into GDAL
+ * geometries.
+ *
+ * @attention If you include this file, you'll need to link with `libgeos`.
+ */
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <geos/geom/Coordinate.h>
+#include <geos/geom/CoordinateSequence.h>
+#include <geos/geom/CoordinateSequenceFactory.h>
+#include <geos/geom/GeometryFactory.h>
+#include <geos/geom/LinearRing.h>
+#include <geos/geom/MultiPolygon.h>
+#include <geos/geom/Point.h>
+#include <geos/geom/Polygon.h>
+#include <geos/geom/PrecisionModel.h>
+#include <geos/util/GEOSException.h>
+
+#include <osmium/geom/factory.hpp>
+#include <osmium/geom/coordinates.hpp>
+
+// MSVC doesn't support throw_with_nested yet
+#ifdef _MSC_VER
+# define THROW throw
+#else
+# define THROW std::throw_with_nested
+#endif
+
+namespace osmium {
+
+    struct geos_geometry_error : public geometry_error {
+
+        geos_geometry_error(const char* message) :
+            geometry_error(std::string("geometry creation failed in GEOS library: ") + message) {
+        }
+
+    }; // struct geos_geometry_error
+
+    namespace geom {
+
+        namespace detail {
+
+            class GEOSFactoryImpl {
+
+                std::unique_ptr<const geos::geom::PrecisionModel> m_precision_model;
+                std::unique_ptr<geos::geom::GeometryFactory> m_our_geos_factory;
+                geos::geom::GeometryFactory* m_geos_factory;
+
+                std::unique_ptr<geos::geom::CoordinateSequence> m_coordinate_sequence;
+                std::vector<std::unique_ptr<geos::geom::LinearRing>> m_rings;
+                std::vector<std::unique_ptr<geos::geom::Polygon>> m_polygons;
+
+            public:
+
+                typedef std::unique_ptr<geos::geom::Point>        point_type;
+                typedef std::unique_ptr<geos::geom::LineString>   linestring_type;
+                typedef std::unique_ptr<geos::geom::Polygon>      polygon_type;
+                typedef std::unique_ptr<geos::geom::MultiPolygon> multipolygon_type;
+                typedef std::unique_ptr<geos::geom::LinearRing>   ring_type;
+
+                explicit GEOSFactoryImpl(geos::geom::GeometryFactory& geos_factory) :
+                    m_precision_model(nullptr),
+                    m_our_geos_factory(nullptr),
+                    m_geos_factory(&geos_factory) {
+                }
+
+                explicit GEOSFactoryImpl(int srid = -1) :
+                    m_precision_model(new geos::geom::PrecisionModel),
+                    m_our_geos_factory(new geos::geom::GeometryFactory(m_precision_model.get(), srid)),
+                    m_geos_factory(m_our_geos_factory.get()) {
+                }
+
+                /* Point */
+
+                point_type make_point(const osmium::geom::Coordinates& xy) const {
+                    try {
+                        return point_type(m_geos_factory->createPoint(geos::geom::Coordinate(xy.x, xy.y)));
+                    } catch (geos::util::GEOSException& e) {
+                        THROW(osmium::geos_geometry_error(e.what()));
+                    }
+                }
+
+                /* LineString */
+
+                void linestring_start() {
+                    try {
+                        m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
+                    } catch (geos::util::GEOSException& e) {
+                        THROW(osmium::geos_geometry_error(e.what()));
+                    }
+                }
+
+                void linestring_add_location(const osmium::geom::Coordinates& xy) {
+                    try {
+                        m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
+                    } catch (geos::util::GEOSException& e) {
+                        THROW(osmium::geos_geometry_error(e.what()));
+                    }
+                }
+
+                linestring_type linestring_finish(size_t /* num_points */) {
+                    try {
+                        return linestring_type(m_geos_factory->createLineString(m_coordinate_sequence.release()));
+                    } catch (geos::util::GEOSException& e) {
+                        THROW(osmium::geos_geometry_error(e.what()));
+                    }
+                }
+
+                /* MultiPolygon */
+
+                void multipolygon_start() {
+                    m_polygons.clear();
+                }
+
+                void multipolygon_polygon_start() {
+                    m_rings.clear();
+                }
+
+                void multipolygon_polygon_finish() {
+                    try {
+                        assert(!m_rings.empty());
+                        auto inner_rings = new std::vector<geos::geom::Geometry*>;
+                        std::transform(std::next(m_rings.begin(), 1), m_rings.end(), std::back_inserter(*inner_rings), [](std::unique_ptr<geos::geom::LinearRing>& r) {
+                            return r.release();
+                        });
+                        m_polygons.emplace_back(m_geos_factory->createPolygon(m_rings[0].release(), inner_rings));
+                        m_rings.clear();
+                    } catch (geos::util::GEOSException& e) {
+                        THROW(osmium::geos_geometry_error(e.what()));
+                    }
+                }
+
+                void multipolygon_outer_ring_start() {
+                    try {
+                        m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
+                    } catch (geos::util::GEOSException& e) {
+                        THROW(osmium::geos_geometry_error(e.what()));
+                    }
+                }
+
+                void multipolygon_outer_ring_finish() {
+                    try {
+                        m_rings.emplace_back(m_geos_factory->createLinearRing(m_coordinate_sequence.release()));
+                    } catch (geos::util::GEOSException& e) {
+                        THROW(osmium::geos_geometry_error(e.what()));
+                    }
+                }
+
+                void multipolygon_inner_ring_start() {
+                    try {
+                        m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
+                    } catch (geos::util::GEOSException& e) {
+                        THROW(osmium::geos_geometry_error(e.what()));
+                    }
+                }
+
+                void multipolygon_inner_ring_finish() {
+                    try {
+                        m_rings.emplace_back(m_geos_factory->createLinearRing(m_coordinate_sequence.release()));
+                    } catch (geos::util::GEOSException& e) {
+                        THROW(osmium::geos_geometry_error(e.what()));
+                    }
+                }
+
+                void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+                    try {
+                        m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
+                    } catch (geos::util::GEOSException& e) {
+                        THROW(osmium::geos_geometry_error(e.what()));
+                    }
+                }
+
+                multipolygon_type multipolygon_finish() {
+                    try {
+                        auto polygons = new std::vector<geos::geom::Geometry*>;
+                        std::transform(m_polygons.begin(), m_polygons.end(), std::back_inserter(*polygons), [](std::unique_ptr<geos::geom::Polygon>& p) {
+                            return p.release();
+                        });
+                        m_polygons.clear();
+                        return multipolygon_type(m_geos_factory->createMultiPolygon(polygons));
+                    } catch (geos::util::GEOSException& e) {
+                        THROW(osmium::geos_geometry_error(e.what()));
+                    }
+                }
+
+            }; // class GEOSFactoryImpl
+
+        } // namespace detail
+
+        template <typename TProjection = IdentityProjection>
+        using GEOSFactory = GeometryFactory<osmium::geom::detail::GEOSFactoryImpl, TProjection>;
+
+    } // namespace geom
+
+} // namespace osmium
+
+#undef THROW
+
+#endif // OSMIUM_GEOM_GEOS_HPP
diff --git a/contrib/libosmium/osmium/geom/haversine.hpp b/contrib/libosmium/osmium/geom/haversine.hpp
new file mode 100644
index 0000000..e62a31b
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/haversine.hpp
@@ -0,0 +1,94 @@
+#ifndef OSMIUM_GEOM_HAVERSINE_HPP
+#define OSMIUM_GEOM_HAVERSINE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cmath>
+#include <iterator>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/util.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        /**
+         * @brief Functions to calculate arc distance on Earth using the haversine formula.
+         *
+         * See http://en.wikipedia.org/wiki/Haversine_formula
+         *
+         * Implementation derived from
+         * http://blog.julien.cayzac.name/2008/10/arc-and-distance-between-two-points-on.html
+         */
+        namespace haversine {
+
+            /// @brief Earth's quadratic mean radius for WGS84
+            constexpr double EARTH_RADIUS_IN_METERS = 6372797.560856;
+
+            /**
+             * Calculate distance in meters between two sets of coordinates.
+             */
+            inline double distance(const osmium::geom::Coordinates& c1, const osmium::geom::Coordinates& c2) {
+                double lonh = sin(deg_to_rad(c1.x - c2.x) * 0.5);
+                lonh *= lonh;
+                double lath = sin(deg_to_rad(c1.y - c2.y) * 0.5);
+                lath *= lath;
+                const double tmp = cos(deg_to_rad(c1.y)) * cos(deg_to_rad(c2.y));
+                return 2.0 * EARTH_RADIUS_IN_METERS * asin(sqrt(lath + tmp*lonh));
+            }
+
+            /**
+             * Calculate length of way.
+             */
+            inline double distance(const osmium::WayNodeList& wnl) {
+                double sum_length = 0;
+
+                for (auto it = wnl.begin(); it != wnl.end(); ++it) {
+                    if (std::next(it) != wnl.end()) {
+                        sum_length += distance(it->location(), std::next(it)->location());
+                    }
+                }
+
+                return sum_length;
+            }
+
+        } // namespace haversine
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_HAVERSINE_HPP
diff --git a/contrib/libosmium/osmium/geom/mercator_projection.hpp b/contrib/libosmium/osmium/geom/mercator_projection.hpp
new file mode 100644
index 0000000..22a0d64
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/mercator_projection.hpp
@@ -0,0 +1,110 @@
+#ifndef OSMIUM_GEOM_MERCATOR_PROJECTION_HPP
+#define OSMIUM_GEOM_MERCATOR_PROJECTION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cmath>
+#include <string>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/util.hpp>
+#include <osmium/osm/location.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        namespace detail {
+
+            constexpr double earth_radius_for_epsg3857 = 6378137.0;
+            constexpr double max_coordinate_epsg3857 = 20037508.34;
+
+            constexpr inline double lon_to_x(double lon) {
+                return earth_radius_for_epsg3857 * deg_to_rad(lon);
+            }
+
+            inline double lat_to_y(double lat) { // not constexpr because math functions aren't
+                return earth_radius_for_epsg3857 * std::log(std::tan(osmium::geom::PI/4 + deg_to_rad(lat)/2));
+            }
+
+            constexpr inline double x_to_lon(double x) {
+                return rad_to_deg(x) / earth_radius_for_epsg3857;
+            }
+
+            inline double y_to_lat(double y) { // not constexpr because math functions aren't
+                return rad_to_deg(2 * std::atan(std::exp(y / earth_radius_for_epsg3857)) - osmium::geom::PI/2);
+            }
+
+        } // namespace detail
+
+        /**
+         * The maximum latitude that can be projected with the Web Mercator
+         * (EPSG:3857) projection.
+         */
+        constexpr double MERCATOR_MAX_LAT = 85.0511288;
+
+        inline Coordinates lonlat_to_mercator(const Coordinates& c) {
+            return Coordinates(detail::lon_to_x(c.x), detail::lat_to_y(c.y));
+        }
+
+        inline Coordinates mercator_to_lonlat(const Coordinates& c) {
+            return Coordinates(detail::x_to_lon(c.x), detail::y_to_lat(c.y));
+        }
+
+        /**
+         * Functor that does projection from WGS84 (EPSG:4326) to "Web
+         * Mercator" (EPSG:3857)
+         */
+        class MercatorProjection {
+
+        public:
+
+            Coordinates operator()(osmium::Location location) const {
+                return Coordinates {detail::lon_to_x(location.lon()), detail::lat_to_y(location.lat())};
+            }
+
+            int epsg() const noexcept {
+                return 3857;
+            }
+
+            std::string proj_string() const {
+                return "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs";
+            }
+
+        }; // class MercatorProjection
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_MERCATOR_PROJECTION_HPP
diff --git a/contrib/libosmium/osmium/geom/ogr.hpp b/contrib/libosmium/osmium/geom/ogr.hpp
new file mode 100644
index 0000000..4d5995c
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/ogr.hpp
@@ -0,0 +1,178 @@
+#ifndef OSMIUM_GEOM_OGR_HPP
+#define OSMIUM_GEOM_OGR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * This file contains code for conversion of OSM geometries into OGR
+ * geometries.
+ *
+ * @attention If you include this file, you'll need to link with `libgdal`.
+ */
+
+#include <cassert>
+#include <cstddef>
+#include <memory>
+#include <utility>
+
+#include <ogr_geometry.h>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/factory.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        namespace detail {
+
+            class OGRFactoryImpl {
+
+            public:
+
+                typedef std::unique_ptr<OGRPoint>        point_type;
+                typedef std::unique_ptr<OGRLineString>   linestring_type;
+                typedef std::unique_ptr<OGRPolygon>      polygon_type;
+                typedef std::unique_ptr<OGRMultiPolygon> multipolygon_type;
+                typedef std::unique_ptr<OGRLinearRing>   ring_type;
+
+            private:
+
+                linestring_type   m_linestring;
+                multipolygon_type m_multipolygon;
+                polygon_type      m_polygon;
+                ring_type         m_ring;
+
+            public:
+
+                OGRFactoryImpl() = default;
+
+                /* Point */
+
+                point_type make_point(const osmium::geom::Coordinates& xy) const {
+                    return point_type(new OGRPoint(xy.x, xy.y));
+                }
+
+                /* LineString */
+
+                void linestring_start() {
+                    m_linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
+                }
+
+                void linestring_add_location(const osmium::geom::Coordinates& xy) {
+                    assert(!!m_linestring);
+                    m_linestring->addPoint(xy.x, xy.y);
+                }
+
+                linestring_type linestring_finish(size_t /* num_points */) {
+                    return std::move(m_linestring);
+                }
+
+                /* Polygon */
+
+                void polygon_start() {
+                    m_ring = std::unique_ptr<OGRLinearRing>(new OGRLinearRing());
+                }
+
+                void polygon_add_location(const osmium::geom::Coordinates& xy) {
+                    assert(!!m_ring);
+                    m_ring->addPoint(xy.x, xy.y);
+                }
+
+                polygon_type polygon_finish(size_t /* num_points */) {
+                    std::unique_ptr<OGRPolygon> polygon = std::unique_ptr<OGRPolygon>(new OGRPolygon());
+                    polygon->addRingDirectly(m_ring.release());
+                    return polygon;
+                }
+
+                /* MultiPolygon */
+
+                void multipolygon_start() {
+                    m_multipolygon.reset(new OGRMultiPolygon());
+                }
+
+                void multipolygon_polygon_start() {
+                    m_polygon.reset(new OGRPolygon());
+                }
+
+                void multipolygon_polygon_finish() {
+                    assert(!!m_multipolygon);
+                    assert(!!m_polygon);
+                    m_multipolygon->addGeometryDirectly(m_polygon.release());
+                }
+
+                void multipolygon_outer_ring_start() {
+                    m_ring.reset(new OGRLinearRing());
+                }
+
+                void multipolygon_outer_ring_finish() {
+                    assert(!!m_polygon);
+                    assert(!!m_ring);
+                    m_polygon->addRingDirectly(m_ring.release());
+                }
+
+                void multipolygon_inner_ring_start() {
+                    m_ring.reset(new OGRLinearRing());
+                }
+
+                void multipolygon_inner_ring_finish() {
+                    assert(!!m_polygon);
+                    assert(!!m_ring);
+                    m_polygon->addRingDirectly(m_ring.release());
+                }
+
+                void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+                    assert(!!m_polygon);
+                    assert(!!m_ring);
+                    m_ring->addPoint(xy.x, xy.y);
+                }
+
+                multipolygon_type multipolygon_finish() {
+                    assert(!!m_multipolygon);
+                    return std::move(m_multipolygon);
+                }
+
+            }; // class OGRFactoryImpl
+
+        } // namespace detail
+
+        template <typename TProjection = IdentityProjection>
+        using OGRFactory = GeometryFactory<osmium::geom::detail::OGRFactoryImpl, TProjection>;
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_OGR_HPP
diff --git a/contrib/libosmium/osmium/geom/projection.hpp b/contrib/libosmium/osmium/geom/projection.hpp
new file mode 100644
index 0000000..6419101
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/projection.hpp
@@ -0,0 +1,167 @@
+#ifndef OSMIUM_GEOM_PROJECTION_HPP
+#define OSMIUM_GEOM_PROJECTION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * This file contains code for projecting OSM locations to arbitrary
+ * coordinate reference systems. It is based on the Proj.4 library.
+ *
+ * @attention If you include this file, you'll need to link with `libproj`.
+ */
+
+#include <memory>
+#include <string>
+
+#include <proj_api.h>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/util.hpp>
+#include <osmium/osm/location.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        /**
+         * C++ wrapper for a Coordinate Reference System of the proj library.
+         */
+        class CRS {
+
+            struct ProjCRSDeleter {
+                void operator()(void* crs) {
+                    pj_free(crs);
+                }
+            }; // struct ProjCRSDeleter
+
+            std::unique_ptr<void, ProjCRSDeleter> m_crs;
+
+            projPJ get() const {
+                return m_crs.get();
+            }
+
+        public:
+
+            CRS(const std::string& crs) :
+                m_crs(pj_init_plus(crs.c_str()), ProjCRSDeleter()) {
+                if (!m_crs) {
+                    throw osmium::projection_error(std::string("creation of CRS failed: ") + pj_strerrno(*pj_get_errno_ref()));
+                }
+            }
+
+            CRS(int epsg) :
+                CRS(std::string("+init=epsg:") + std::to_string(epsg)) {
+            }
+
+            bool is_latlong() const {
+                return pj_is_latlong(m_crs.get()) != 0;
+            }
+
+            bool is_geocent() const {
+                return pj_is_geocent(m_crs.get()) != 0;
+            }
+
+            /**
+             * Transform coordinates from one CRS into another. Wraps the same function
+             * of the proj library.
+             *
+             * Coordinates have to be in radians and are produced in radians.
+             *
+             * @throws osmmium::projection_error if the projection fails
+             */
+            friend Coordinates transform(const CRS& src, const CRS& dest, Coordinates c) {
+                int result = pj_transform(src.get(), dest.get(), 1, 1, &c.x, &c.y, nullptr);
+                if (result != 0) {
+                    throw osmium::projection_error(std::string("projection failed: ") + pj_strerrno(result));
+                }
+                return c;
+            }
+
+        }; // class CRS
+
+        /**
+         * Functor that does projection from WGS84 (EPSG:4326) to the given
+         * CRS.
+         */
+        class Projection {
+
+            int m_epsg;
+            std::string m_proj_string;
+            CRS m_crs_wgs84 {4326};
+            CRS m_crs_user;
+
+        public:
+
+            Projection(const std::string& proj_string) :
+                m_epsg(-1),
+                m_proj_string(proj_string),
+                m_crs_user(proj_string) {
+            }
+
+            Projection(int epsg) :
+                m_epsg(epsg),
+                m_proj_string(std::string("+init=epsg:") + std::to_string(epsg)),
+                m_crs_user(epsg) {
+            }
+
+            Coordinates operator()(osmium::Location location) const {
+                Coordinates c {location.lon(), location.lat()};
+
+                if (m_epsg != 4326) {
+                    c = transform(m_crs_wgs84, m_crs_user, Coordinates(deg_to_rad(location.lon()), deg_to_rad(location.lat())));
+                    if (m_crs_user.is_latlong()) {
+                        c.x = rad_to_deg(c.x);
+                        c.y = rad_to_deg(c.y);
+                    }
+                }
+
+                return c;
+            }
+
+            int epsg() const noexcept {
+                return m_epsg;
+            }
+
+            std::string proj_string() const {
+                return m_proj_string;
+            }
+
+        }; // class Projection
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_PROJECTION_HPP
diff --git a/contrib/libosmium/osmium/geom/rapid_geojson.hpp b/contrib/libosmium/osmium/geom/rapid_geojson.hpp
new file mode 100644
index 0000000..87e479b
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/rapid_geojson.hpp
@@ -0,0 +1,190 @@
+#ifndef OSMIUM_GEOM_RAPID_GEOJSON_HPP
+#define OSMIUM_GEOM_RAPID_GEOJSON_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/factory.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        namespace detail {
+
+            /**
+             * A geometry factory implementation that can be used with the
+             * RapidJSON (https://github.com/miloyip/rapidjson) JSON writer.
+             */
+            template <typename TWriter>
+            class RapidGeoJSONFactoryImpl {
+
+                TWriter* m_writer;
+
+            public:
+
+                typedef void point_type;
+                typedef void linestring_type;
+                typedef void polygon_type;
+                typedef void multipolygon_type;
+                typedef void ring_type;
+
+                RapidGeoJSONFactoryImpl(TWriter& writer) :
+                    m_writer(&writer) {
+                }
+
+                /* Point */
+
+                // { "type": "Point", "coordinates": [100.0, 0.0] }
+                point_type make_point(const osmium::geom::Coordinates& xy) const {
+                    m_writer->String("geometry");
+                    m_writer->StartObject();
+                    m_writer->String("type");
+                    m_writer->String("Point");
+                    m_writer->String("coordinates");
+                    m_writer->StartArray();
+                    m_writer->Double(xy.x);
+                    m_writer->Double(xy.y);
+                    m_writer->EndArray();
+                    m_writer->EndObject();
+                }
+
+                /* LineString */
+
+                // { "type": "LineString", "coordinates": [ [100.0, 0.0], [101.0, 1.0] ] }
+                void linestring_start() {
+                    m_writer->String("geometry");
+                    m_writer->StartObject();
+                    m_writer->String("type");
+                    m_writer->String("LineString");
+                    m_writer->String("coordinates");
+                    m_writer->StartArray();
+                }
+
+                void linestring_add_location(const osmium::geom::Coordinates& xy) {
+                    m_writer->StartArray();
+                    m_writer->Double(xy.x);
+                    m_writer->Double(xy.y);
+                    m_writer->EndArray();
+                }
+
+                linestring_type linestring_finish(size_t /* num_points */) {
+                    m_writer->EndArray();
+                    m_writer->EndObject();
+                }
+
+                /* Polygon */
+
+                // { "type": "Polygon", "coordinates": [[[100.0, 0.0], [101.0, 1.0]]] }
+                void polygon_start() {
+                    m_writer->String("geometry");
+                    m_writer->StartObject();
+                    m_writer->String("type");
+                    m_writer->String("Polygon");
+                    m_writer->String("coordinates");
+                    m_writer->StartArray();
+                    m_writer->StartArray();
+                }
+
+                void polygon_add_location(const osmium::geom::Coordinates& xy) {
+                    m_writer->StartArray();
+                    m_writer->Double(xy.x);
+                    m_writer->Double(xy.y);
+                    m_writer->EndArray();
+                }
+
+                polygon_type polygon_finish(size_t /* num_points */) {
+                    m_writer->EndArray();
+                    m_writer->EndArray();
+                    m_writer->EndObject();
+                }
+
+                /* MultiPolygon */
+
+                void multipolygon_start() {
+                    m_writer->String("geometry");
+                    m_writer->StartObject();
+                    m_writer->String("type");
+                    m_writer->String("MultiPolygon");
+                    m_writer->String("coordinates");
+                    m_writer->StartArray();
+                }
+
+                void multipolygon_polygon_start() {
+                    m_writer->StartArray();
+                }
+
+                void multipolygon_polygon_finish() {
+                    m_writer->EndArray();
+                }
+
+                void multipolygon_outer_ring_start() {
+                    m_writer->StartArray();
+                }
+
+                void multipolygon_outer_ring_finish() {
+                    m_writer->EndArray();
+                }
+
+                void multipolygon_inner_ring_start() {
+                    m_writer->StartArray();
+                }
+
+                void multipolygon_inner_ring_finish() {
+                    m_writer->EndArray();
+                }
+
+                void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+                    m_writer->StartArray();
+                    m_writer->Double(xy.x);
+                    m_writer->Double(xy.y);
+                    m_writer->EndArray();
+                }
+
+                multipolygon_type multipolygon_finish() {
+                    m_writer->EndArray();
+                    m_writer->EndObject();
+                }
+
+            }; // class RapidGeoJSONFactoryImpl
+
+        } // namespace detail
+
+        template <typename TWriter, typename TProjection = IdentityProjection>
+        using RapidGeoJSONFactory = GeometryFactory<detail::RapidGeoJSONFactoryImpl<TWriter>, TProjection>;
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_RAPID_GEOJSON_HPP
diff --git a/contrib/libosmium/osmium/geom/relations.hpp b/contrib/libosmium/osmium/geom/relations.hpp
new file mode 100644
index 0000000..e9e2aa4
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/relations.hpp
@@ -0,0 +1,57 @@
+#ifndef OSMIUM_GEOM_RELATIONS_HPP
+#define OSMIUM_GEOM_RELATIONS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/location.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        /**
+         * Check whether one geometry contains another.
+         */
+        inline bool contains(const osmium::Box& a, const osmium::Box& b) {
+            return ((a.bottom_left().x() >= b.bottom_left().x()) &&
+                    (a.top_right().x()   <= b.top_right().x())   &&
+                    (a.bottom_left().y() >= b.bottom_left().y()) &&
+                    (a.top_right().y()   <= b.top_right().y()));
+        }
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_RELATIONS_HPP
diff --git a/contrib/libosmium/osmium/geom/tile.hpp b/contrib/libosmium/osmium/geom/tile.hpp
new file mode 100644
index 0000000..6ca0682
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/tile.hpp
@@ -0,0 +1,101 @@
+#ifndef OSMIUM_GEOM_TILE_HPP
+#define OSMIUM_GEOM_TILE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdint>
+
+#include <osmium/geom/mercator_projection.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        namespace detail {
+
+            template <typename T>
+            inline T restrict_to_range(T value, T min, T max) {
+                if (value < min) return min;
+                if (value > max) return max;
+                return value;
+            }
+
+        } // namespace detail
+
+        /**
+         * A tile in the usual Mercator projection.
+         */
+        struct Tile {
+
+            uint32_t x;
+            uint32_t y;
+            uint32_t z;
+
+            explicit Tile(uint32_t zoom, uint32_t tx, uint32_t ty) noexcept : x(tx), y(ty), z(zoom) {
+            }
+
+            explicit Tile(uint32_t zoom, const osmium::Location& location) :
+                z(zoom) {
+                osmium::geom::Coordinates c = lonlat_to_mercator(location);
+                const int32_t n = 1 << zoom;
+                const double scale = detail::max_coordinate_epsg3857 * 2 / n;
+                x = uint32_t(detail::restrict_to_range<int32_t>(int32_t((c.x + detail::max_coordinate_epsg3857) / scale), 0, n-1));
+                y = uint32_t(detail::restrict_to_range<int32_t>(int32_t((detail::max_coordinate_epsg3857 - c.y) / scale), 0, n-1));
+            }
+
+        }; // struct Tile
+
+        inline bool operator==(const Tile& a, const Tile& b) {
+            return a.z == b.z && a.x == b.x && a.y == b.y;
+        }
+
+        inline bool operator!=(const Tile& a, const Tile& b) {
+            return ! (a == b);
+        }
+
+        /**
+         * This defines an arbitrary order on tiles for use in std::map etc.
+         */
+        inline bool operator<(const Tile& a, const Tile& b) {
+            if (a.z < b.z) return true;
+            if (a.z > b.z) return false;
+            if (a.x < b.x) return true;
+            if (a.x > b.x) return false;
+            return a.y < b.y;
+        }
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_TILE_HPP
diff --git a/contrib/libosmium/osmium/geom/util.hpp b/contrib/libosmium/osmium/geom/util.hpp
new file mode 100644
index 0000000..5e9f822
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/util.hpp
@@ -0,0 +1,75 @@
+#ifndef OSMIUM_GEOM_UTIL_HPP
+#define OSMIUM_GEOM_UTIL_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <stdexcept>
+#include <string>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when a projection object can not be initialized or the
+     * projection of some coordinates can not be calculated.
+     */
+    struct projection_error : public std::runtime_error {
+
+        projection_error(const std::string& what) :
+            std::runtime_error(what) {
+        }
+
+        projection_error(const char* what) :
+            std::runtime_error(what) {
+        }
+
+    }; // struct projection_error
+
+    namespace geom {
+
+        constexpr double PI = 3.14159265358979323846;
+
+        /// Convert angle from degrees to radians.
+        inline constexpr double deg_to_rad(double degree) noexcept {
+            return degree * (PI / 180.0);
+        }
+
+        /// Convert angle from radians to degrees.
+        inline constexpr double rad_to_deg(double radians) noexcept {
+            return radians * (180.0 / PI);
+        }
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_UTIL_HPP
diff --git a/contrib/libosmium/osmium/geom/wkb.hpp b/contrib/libosmium/osmium/geom/wkb.hpp
new file mode 100644
index 0000000..49833e6
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/wkb.hpp
@@ -0,0 +1,273 @@
+#ifndef OSMIUM_GEOM_WKB_HPP
+#define OSMIUM_GEOM_WKB_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/factory.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/util/endian.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        enum class wkb_type : bool {
+            wkb  = false,
+            ewkb = true
+        }; // enum class wkb_type
+
+        enum class out_type : bool {
+            binary = false,
+            hex    = true
+        }; // enum class out_type
+
+        namespace detail {
+
+            template <typename T>
+            inline void str_push(std::string& str, T data) {
+                size_t size = str.size();
+                str.resize(size + sizeof(T));
+                std::copy_n(reinterpret_cast<char*>(&data), sizeof(T), &str[size]);
+            }
+
+            inline std::string convert_to_hex(const std::string& str) {
+                static const char* lookup_hex = "0123456789ABCDEF";
+                std::string out;
+
+                for (char c : str) {
+                    out += lookup_hex[(c >> 4) & 0xf];
+                    out += lookup_hex[c & 0xf];
+                }
+
+                return out;
+            }
+
+            class WKBFactoryImpl {
+
+                /// OSM data always uses SRID 4326 (WGS84).
+                static constexpr uint32_t srid = 4326;
+
+                /**
+                * Type of WKB geometry.
+                * These definitions are from
+                * 99-049_OpenGIS_Simple_Features_Specification_For_SQL_Rev_1.1.pdf (for WKB)
+                * and http://trac.osgeo.org/postgis/browser/trunk/doc/ZMSgeoms.txt (for EWKB).
+                * They are used to encode geometries into the WKB format.
+                */
+                enum wkbGeometryType : uint32_t {
+                    wkbPoint               = 1,
+                    wkbLineString          = 2,
+                    wkbPolygon             = 3,
+                    wkbMultiPoint          = 4,
+                    wkbMultiLineString     = 5,
+                    wkbMultiPolygon        = 6,
+                    wkbGeometryCollection  = 7,
+
+                    // SRID-presence flag (EWKB)
+                    wkbSRID                = 0x20000000
+                }; // enum wkbGeometryType
+
+                /**
+                * Byte order marker in WKB geometry.
+                */
+                enum class wkb_byte_order_type : uint8_t {
+                    XDR = 0,         // Big Endian
+                    NDR = 1          // Little Endian
+                }; // enum class wkb_byte_order_type
+
+                std::string m_data;
+                uint32_t m_points {0};
+                wkb_type m_wkb_type;
+                out_type m_out_type;
+
+                size_t m_linestring_size_offset = 0;
+                size_t m_polygons = 0;
+                size_t m_rings = 0;
+                size_t m_multipolygon_size_offset = 0;
+                size_t m_polygon_size_offset = 0;
+                size_t m_ring_size_offset = 0;
+
+                size_t header(std::string& str, wkbGeometryType type, bool add_length) const {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+                    str_push(str, wkb_byte_order_type::NDR);
+#else
+                    str_push(str, wkb_byte_order_type::XDR);
+#endif
+                    if (m_wkb_type == wkb_type::ewkb) {
+                        str_push(str, type | wkbSRID);
+                        str_push(str, srid);
+                    } else {
+                        str_push(str, type);
+                    }
+                    size_t offset = str.size();
+                    if (add_length) {
+                        str_push(str, static_cast<uint32_t>(0));
+                    }
+                    return offset;
+                }
+
+                void set_size(const size_t offset, const size_t size) {
+                    *reinterpret_cast<uint32_t*>(&m_data[offset]) = static_cast_with_assert<uint32_t>(size);
+                }
+
+            public:
+
+                typedef std::string point_type;
+                typedef std::string linestring_type;
+                typedef std::string polygon_type;
+                typedef std::string multipolygon_type;
+                typedef std::string ring_type;
+
+                explicit WKBFactoryImpl(wkb_type wtype = wkb_type::wkb, out_type otype = out_type::binary) :
+                    m_wkb_type(wtype),
+                    m_out_type(otype) {
+                }
+
+                /* Point */
+
+                point_type make_point(const osmium::geom::Coordinates& xy) const {
+                    std::string data;
+                    header(data, wkbPoint, false);
+                    str_push(data, xy.x);
+                    str_push(data, xy.y);
+
+                    if (m_out_type == out_type::hex) {
+                        return convert_to_hex(data);
+                    } else {
+                        return data;
+                    }
+                }
+
+                /* LineString */
+
+                void linestring_start() {
+                    m_data.clear();
+                    m_linestring_size_offset = header(m_data, wkbLineString, true);
+                }
+
+                void linestring_add_location(const osmium::geom::Coordinates& xy) {
+                    str_push(m_data, xy.x);
+                    str_push(m_data, xy.y);
+                }
+
+                linestring_type linestring_finish(size_t num_points) {
+                    set_size(m_linestring_size_offset, num_points);
+                    std::string data;
+
+                    using std::swap;
+                    swap(data, m_data);
+
+                    if (m_out_type == out_type::hex) {
+                        return convert_to_hex(data);
+                    } else {
+                        return data;
+                    }
+                }
+
+                /* MultiPolygon */
+
+                void multipolygon_start() {
+                    m_data.clear();
+                    m_polygons = 0;
+                    m_multipolygon_size_offset = header(m_data, wkbMultiPolygon, true);
+                }
+
+                void multipolygon_polygon_start() {
+                    ++m_polygons;
+                    m_rings = 0;
+                    m_polygon_size_offset = header(m_data, wkbPolygon, true);
+                }
+
+                void multipolygon_polygon_finish() {
+                    set_size(m_polygon_size_offset, m_rings);
+                }
+
+                void multipolygon_outer_ring_start() {
+                    ++m_rings;
+                    m_points = 0;
+                    m_ring_size_offset = m_data.size();
+                    str_push(m_data, static_cast<uint32_t>(0));
+                }
+
+                void multipolygon_outer_ring_finish() {
+                    set_size(m_ring_size_offset, m_points);
+                }
+
+                void multipolygon_inner_ring_start() {
+                    ++m_rings;
+                    m_points = 0;
+                    m_ring_size_offset = m_data.size();
+                    str_push(m_data, static_cast<uint32_t>(0));
+                }
+
+                void multipolygon_inner_ring_finish() {
+                    set_size(m_ring_size_offset, m_points);
+                }
+
+                void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+                    str_push(m_data, xy.x);
+                    str_push(m_data, xy.y);
+                    ++m_points;
+                }
+
+                multipolygon_type multipolygon_finish() {
+                    set_size(m_multipolygon_size_offset, m_polygons);
+                    std::string data;
+
+                    using std::swap;
+                    swap(data, m_data);
+
+                    if (m_out_type == out_type::hex) {
+                        return convert_to_hex(data);
+                    } else {
+                        return data;
+                    }
+                }
+
+            }; // class WKBFactoryImpl
+
+        } // namespace detail
+
+        template <typename TProjection = IdentityProjection>
+        using WKBFactory = GeometryFactory<osmium::geom::detail::WKBFactoryImpl, TProjection>;
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_WKB_HPP
diff --git a/contrib/libosmium/osmium/geom/wkt.hpp b/contrib/libosmium/osmium/geom/wkt.hpp
new file mode 100644
index 0000000..9cf5371
--- /dev/null
+++ b/contrib/libosmium/osmium/geom/wkt.hpp
@@ -0,0 +1,156 @@
+#ifndef OSMIUM_GEOM_WKT_HPP
+#define OSMIUM_GEOM_WKT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstddef>
+#include <string>
+#include <utility>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/factory.hpp>
+
+namespace osmium {
+
+    namespace geom {
+
+        namespace detail {
+
+            class WKTFactoryImpl {
+
+                std::string m_str;
+                int m_precision;
+
+            public:
+
+                typedef std::string point_type;
+                typedef std::string linestring_type;
+                typedef std::string polygon_type;
+                typedef std::string multipolygon_type;
+                typedef std::string ring_type;
+
+                WKTFactoryImpl(int precision = 7) :
+                    m_precision(precision) {
+                }
+
+                /* Point */
+
+                point_type make_point(const osmium::geom::Coordinates& xy) const {
+                    std::string str {"POINT"};
+                    xy.append_to_string(str, '(', ' ', ')', m_precision);
+                    return str;
+                }
+
+                /* LineString */
+
+                void linestring_start() {
+                    m_str = "LINESTRING(";
+                }
+
+                void linestring_add_location(const osmium::geom::Coordinates& xy) {
+                    xy.append_to_string(m_str, ' ', m_precision);
+                    m_str += ',';
+                }
+
+                linestring_type linestring_finish(size_t /* num_points */) {
+                    assert(!m_str.empty());
+                    std::string str;
+
+                    using std::swap;
+                    swap(str, m_str);
+
+                    str.back() = ')';
+                    return str;
+                }
+
+                /* MultiPolygon */
+
+                void multipolygon_start() {
+                    m_str = "MULTIPOLYGON(";
+                }
+
+                void multipolygon_polygon_start() {
+                    m_str += '(';
+                }
+
+                void multipolygon_polygon_finish() {
+                    m_str += "),";
+                }
+
+                void multipolygon_outer_ring_start() {
+                    m_str += '(';
+                }
+
+                void multipolygon_outer_ring_finish() {
+                    assert(!m_str.empty());
+                    m_str.back() = ')';
+                }
+
+                void multipolygon_inner_ring_start() {
+                    m_str += ",(";
+                }
+
+                void multipolygon_inner_ring_finish() {
+                    assert(!m_str.empty());
+                    m_str.back() = ')';
+                }
+
+                void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+                    xy.append_to_string(m_str, ' ', m_precision);
+                    m_str += ',';
+                }
+
+                multipolygon_type multipolygon_finish() {
+                    assert(!m_str.empty());
+                    std::string str;
+
+                    using std::swap;
+                    swap(str, m_str);
+
+                    str.back() = ')';
+                    return str;
+                }
+
+            }; // class WKTFactoryImpl
+
+        } // namespace detail
+
+        template <typename TProjection = IdentityProjection>
+        using WKTFactory = GeometryFactory<osmium::geom::detail::WKTFactoryImpl, TProjection>;
+
+    } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_WKT_HPP
diff --git a/contrib/libosmium/osmium/handler.hpp b/contrib/libosmium/osmium/handler.hpp
new file mode 100644
index 0000000..f366197
--- /dev/null
+++ b/contrib/libosmium/osmium/handler.hpp
@@ -0,0 +1,94 @@
+#ifndef OSMIUM_HANDLER_HPP
+#define OSMIUM_HANDLER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/fwd.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Osmium handlers provide callbacks for OSM objects
+     */
+    namespace handler {
+
+        class Handler {
+
+        public:
+
+            void osm_object(const osmium::OSMObject&) const {
+            }
+
+            void node(const osmium::Node&) const {
+            }
+
+            void way(const osmium::Way&) const {
+            }
+
+            void relation(const osmium::Relation&) const {
+            }
+
+            void area(const osmium::Area&) const {
+            }
+
+            void changeset(const osmium::Changeset&) const {
+            }
+
+            void tag_list(const osmium::TagList&) const {
+            }
+
+            void way_node_list(const osmium::WayNodeList&) const {
+            }
+
+            void relation_member_list(const osmium::RelationMemberList&) const {
+            }
+
+            void outer_ring(const osmium::OuterRing&) const {
+            }
+
+            void inner_ring(const osmium::InnerRing&) const {
+            }
+
+            void changeset_discussion(const osmium::ChangesetDiscussion&) const {
+            }
+
+            void flush() const {
+            }
+
+        }; // class Handler
+
+    } // namspace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_HPP
diff --git a/contrib/libosmium/osmium/handler/chain.hpp b/contrib/libosmium/osmium/handler/chain.hpp
new file mode 100644
index 0000000..4f3291c
--- /dev/null
+++ b/contrib/libosmium/osmium/handler/chain.hpp
@@ -0,0 +1,128 @@
+#ifndef OSMIUM_HANDLER_CHAIN_HPP
+#define OSMIUM_HANDLER_CHAIN_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <tuple>
+
+#include <osmium/handler.hpp>
+
+#define OSMIUM_CHAIN_HANDLER_CALL(_func_, _type_) \
+    template <int N, int SIZE, typename THandlers> \
+    struct call_ ## _func_ { \
+        void operator()(THandlers& handlers, osmium::_type_& object) { \
+            std::get<N>(handlers)._func_(object); \
+            call_ ## _func_<N+1, SIZE, THandlers>()(handlers, object); \
+        } \
+    }; \
+    template <int SIZE, typename THandlers> \
+    struct call_ ## _func_<SIZE, SIZE, THandlers> { \
+        void operator()(THandlers&, osmium::_type_&) {} \
+    };
+
+namespace osmium {
+
+    class Node;
+    class Way;
+    class Relation;
+    class Area;
+    class Changeset;
+
+    namespace handler {
+
+        /**
+         * This handler allows chaining of any number of handlers into a single
+         * handler.
+         */
+        template <typename... THandler>
+        class ChainHandler : public osmium::handler::Handler {
+
+            typedef std::tuple<THandler&...> handlers_type;
+            handlers_type m_handlers;
+
+            template <int N, int SIZE, typename THandlers>
+            struct call_flush {
+                void operator()(THandlers& handlers) {
+                    std::get<N>(handlers).flush();
+                    call_flush<N+1, SIZE, THandlers>()(handlers);
+                }
+            }; // struct call_flush
+
+            template <int SIZE, typename THandlers>
+            struct call_flush<SIZE, SIZE, THandlers> {
+                void operator()(THandlers&) {}
+            }; // struct call_flush
+
+            OSMIUM_CHAIN_HANDLER_CALL(node, Node)
+            OSMIUM_CHAIN_HANDLER_CALL(way, Way)
+            OSMIUM_CHAIN_HANDLER_CALL(relation, Relation)
+            OSMIUM_CHAIN_HANDLER_CALL(changeset, Changeset)
+            OSMIUM_CHAIN_HANDLER_CALL(area, Area)
+
+        public:
+
+            explicit ChainHandler(THandler&... handlers) :
+                m_handlers(handlers...) {
+            }
+
+            void node(osmium::Node& node) {
+                call_node<0, sizeof...(THandler), handlers_type>()(m_handlers, node);
+            }
+
+            void way(osmium::Way& way) {
+                call_way<0, sizeof...(THandler), handlers_type>()(m_handlers, way);
+            }
+
+            void relation(osmium::Relation& relation) {
+                call_relation<0, sizeof...(THandler), handlers_type>()(m_handlers, relation);
+            }
+
+            void changeset( osmium::Changeset& changeset) {
+                call_changeset<0, sizeof...(THandler), handlers_type>()(m_handlers, changeset);
+            }
+
+            void area(osmium::Area& area) {
+                call_area<0, sizeof...(THandler), handlers_type>()(m_handlers, area);
+            }
+
+            void flush() {
+                call_flush<0, sizeof...(THandler), handlers_type>()(m_handlers);
+            }
+
+        }; // class ChainHandler
+
+    } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_CHAIN_HPP
diff --git a/contrib/libosmium/osmium/handler/disk_store.hpp b/contrib/libosmium/osmium/handler/disk_store.hpp
new file mode 100644
index 0000000..ccae596
--- /dev/null
+++ b/contrib/libosmium/osmium/handler/disk_store.hpp
@@ -0,0 +1,111 @@
+#ifndef OSMIUM_HANDLER_DISK_STORE_HPP
+#define OSMIUM_HANDLER_DISK_STORE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+
+#include <osmium/handler.hpp>
+#include <osmium/index/map.hpp>
+#include <osmium/io/detail/read_write.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/item_iterator.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+    namespace handler {
+
+        /**
+         *
+         * Note: This handler will only work if either all object IDs are
+         *       positive or all object IDs are negative.
+         */
+        class DiskStore : public osmium::handler::Handler {
+
+            typedef osmium::index::map::Map<unsigned_object_id_type, size_t> offset_index_type;
+
+            size_t m_offset = 0;
+            int m_data_fd;
+
+            offset_index_type& m_node_index;
+            offset_index_type& m_way_index;
+            offset_index_type& m_relation_index;
+
+        public:
+
+            explicit DiskStore(int data_fd, offset_index_type& node_index, offset_index_type& way_index, offset_index_type& relation_index) :
+                m_data_fd(data_fd),
+                m_node_index(node_index),
+                m_way_index(way_index),
+                m_relation_index(relation_index) {
+            }
+
+            DiskStore(const DiskStore&) = delete;
+            DiskStore& operator=(const DiskStore&) = delete;
+
+            ~DiskStore() noexcept = default;
+
+            void node(const osmium::Node& node) {
+                m_node_index.set(node.positive_id(), m_offset);
+                m_offset += node.byte_size();
+            }
+
+            void way(const osmium::Way& way) {
+                m_way_index.set(way.positive_id(), m_offset);
+                m_offset += way.byte_size();
+            }
+
+            void relation(const osmium::Relation& relation) {
+                m_relation_index.set(relation.positive_id(), m_offset);
+                m_offset += relation.byte_size();
+            }
+
+            // XXX
+            void operator()(const osmium::memory::Buffer& buffer) {
+                osmium::io::detail::reliable_write(m_data_fd, buffer.data(), buffer.committed());
+
+                osmium::apply(buffer.begin(), buffer.end(), *this);
+            }
+
+        }; // class DiskStore
+
+    } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_DISK_STORE_HPP
diff --git a/contrib/libosmium/osmium/handler/dump.hpp b/contrib/libosmium/osmium/handler/dump.hpp
new file mode 100644
index 0000000..a23236e
--- /dev/null
+++ b/contrib/libosmium/osmium/handler/dump.hpp
@@ -0,0 +1,294 @@
+#ifndef OSMIUM_HANDLER_DUMP_HPP
+#define OSMIUM_HANDLER_DUMP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iomanip>
+#include <iostream>
+#include <string>
+
+#include <osmium/handler.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/area.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/changeset.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+    namespace handler {
+
+        class Dump : public osmium::handler::Handler {
+
+            std::ostream* m_out;
+            bool m_with_size;
+            std::string m_prefix;
+
+            void print_title(const char* title, const osmium::memory::Item& item) {
+                *m_out << m_prefix
+                       << title
+                       << ":";
+
+                if (m_with_size) {
+                    *m_out << " ["
+                           << item.byte_size()
+                           << "]";
+                }
+
+                *m_out << "\n";
+            }
+
+            void print_meta(const osmium::OSMObject& object) {
+                *m_out << m_prefix
+                       << "  id="
+                       << object.id()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  version="
+                       << object.version()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  uid="
+                       << object.uid()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  user=|"
+                       << object.user()
+                       << "|\n";
+                *m_out << m_prefix
+                       << "  changeset="
+                       << object.changeset()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  timestamp="
+                       << object.timestamp().to_iso()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  visible="
+                       << (object.visible() ? "yes" : "no")
+                       << "\n";
+
+                Dump dump(*m_out, m_with_size, m_prefix + "  ");
+                osmium::apply(object.cbegin(), object.cend(), dump);
+            }
+
+            void print_location(const osmium::Node& node) {
+                const osmium::Location& location = node.location();
+
+                if (location) {
+                    *m_out << m_prefix
+                           << "  lon="
+                           << std::fixed
+                           << std::setprecision(7)
+                           << location.lon_without_check()
+                           << "\n";
+                    *m_out << m_prefix
+                           << "  lat="
+                           << location.lat_without_check()
+                           << "\n";
+                } else {
+                    *m_out << m_prefix
+                           << "  lon=\n"
+                           << m_prefix
+                           << "  lat=\n";
+                }
+            }
+
+        public:
+
+            explicit Dump(std::ostream& out, bool with_size = true, const std::string& prefix = "") :
+                m_out(&out),
+                m_with_size(with_size),
+                m_prefix(prefix) {
+            }
+
+            void tag_list(const osmium::TagList& tags) {
+                print_title("TAGS", tags);
+                for (const auto& tag : tags) {
+                    *m_out << m_prefix
+                           << "  k=|"
+                           << tag.key()
+                           << "| v=|"
+                           << tag.value()
+                           << "|"
+                           << "\n";
+                }
+            }
+
+            void way_node_list(const osmium::WayNodeList& wnl) {
+                print_title("NODES", wnl);
+                for (const auto& node_ref : wnl) {
+                    *m_out << m_prefix
+                           << "  ref="
+                           << node_ref.ref();
+                    if (node_ref.location()) {
+                        *m_out << " pos="
+                               << node_ref.location();
+                    }
+                    *m_out << "\n";
+                }
+            }
+
+            void relation_member_list(const osmium::RelationMemberList& rml) {
+                print_title("MEMBERS", rml);
+                for (const auto& member : rml) {
+                    *m_out << m_prefix
+                           << "  type="
+                           << item_type_to_name(member.type())
+                           << " ref="
+                           << member.ref()
+                           << " role=|"
+                           << member.role()
+                           << "|\n";
+                    if (member.full_member()) {
+                        Dump dump(*m_out, m_with_size, m_prefix + "  | ");
+                        osmium::apply_item(member.get_object(), dump);
+                    }
+                }
+            }
+
+            void outer_ring(const osmium::OuterRing& ring) {
+                print_title("OUTER RING", ring);
+                for (const auto& node_ref : ring) {
+                    *m_out << m_prefix
+                           << "  ref="
+                           << node_ref.ref();
+                    if (node_ref.location()) {
+                        *m_out << " pos="
+                               << node_ref.location();
+                    }
+                    *m_out << "\n";
+                }
+            }
+
+            void inner_ring(const osmium::InnerRing& ring) {
+                print_title("INNER RING", ring);
+                for (const auto& node_ref : ring) {
+                    *m_out << m_prefix
+                           << "  ref="
+                           << node_ref.ref();
+                    if (node_ref.location()) {
+                        *m_out << " pos="
+                               << node_ref.location();
+                    }
+                    *m_out << "\n";
+                }
+            }
+
+            void node(const osmium::Node& node) {
+                print_title("NODE", node);
+                print_meta(node);
+                print_location(node);
+            }
+
+            void way(const osmium::Way& way) {
+                print_title("WAY", way);
+                print_meta(way);
+            }
+
+            void relation(const osmium::Relation& relation) {
+                print_title("RELATION", relation);
+                print_meta(relation);
+            }
+
+            void area(const osmium::Area& area) {
+                print_title("AREA", area);
+                print_meta(area);
+            }
+
+            void changeset(const osmium::Changeset& changeset) {
+                print_title("CHANGESET", changeset);
+                *m_out << m_prefix
+                       << "  id="
+                       << changeset.id()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  num_changes="
+                       << changeset.num_changes()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  uid="
+                       << changeset.uid()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  user=|"
+                       << changeset.user()
+                       << "|\n";
+                *m_out << m_prefix
+                       << "  created_at="
+                       << changeset.created_at().to_iso()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  closed_at="
+                       << changeset.closed_at().to_iso()
+                       << "\n";
+                *m_out << m_prefix
+                       << "  bounds=";
+
+                if (changeset.bounds()) {
+                    *m_out << '('
+                           << changeset.bounds().bottom_left().lon_without_check()
+                           << ','
+                           << changeset.bounds().bottom_left().lat_without_check()
+                           << ','
+                           << changeset.bounds().top_right().lon_without_check()
+                           << ','
+                           << changeset.bounds().top_right().lat_without_check()
+                           << ')';
+                } else {
+                    *m_out << "(undefined)";
+                }
+
+                *m_out << "\n";
+
+                Dump dump(*m_out, m_with_size, m_prefix + "  ");
+                osmium::apply(changeset.cbegin(), changeset.cend(), dump);
+            }
+
+        }; // class Dump
+
+    } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_DUMP_HPP
diff --git a/contrib/libosmium/osmium/handler/node_locations_for_ways.hpp b/contrib/libosmium/osmium/handler/node_locations_for_ways.hpp
new file mode 100644
index 0000000..8d31310
--- /dev/null
+++ b/contrib/libosmium/osmium/handler/node_locations_for_ways.hpp
@@ -0,0 +1,180 @@
+#ifndef OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP
+#define OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <type_traits>
+
+#include <osmium/handler.hpp>
+#include <osmium/index/index.hpp>
+#include <osmium/index/map/dummy.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
+
+#include <osmium/index/node_locations_map.hpp>
+
+namespace osmium {
+
+    namespace handler {
+
+        typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> dummy_type;
+
+        /**
+         * Handler to retrieve locations from nodes and add them to ways.
+         *
+         * @tparam TStoragePosIDs Class that handles the actual storage of the node locations
+         *                        (for positive IDs). It must support the set(id, value) and
+         *                        get(id) methods.
+         * @tparam TStorageNegIDs Same but for negative IDs.
+         */
+        template <typename TStoragePosIDs, typename TStorageNegIDs = dummy_type>
+        class NodeLocationsForWays : public osmium::handler::Handler {
+
+            static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStoragePosIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
+
+            static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStorageNegIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
+
+        public:
+
+            typedef TStoragePosIDs index_pos_type;
+            typedef TStorageNegIDs index_neg_type;
+
+        private:
+
+            /// Object that handles the actual storage of the node locations (with positive IDs).
+            TStoragePosIDs& m_storage_pos;
+
+            /// Object that handles the actual storage of the node locations (with negative IDs).
+            TStorageNegIDs& m_storage_neg;
+
+            bool m_ignore_errors {false};
+
+            bool m_must_sort {false};
+
+            // It is okay to have this static dummy instance, even when using several threads,
+            // because it is read-only.
+            static dummy_type& get_dummy() {
+                static dummy_type instance;
+                return instance;
+            }
+
+        public:
+
+            explicit NodeLocationsForWays(TStoragePosIDs& storage_pos,
+                                          TStorageNegIDs& storage_neg = get_dummy()) :
+                m_storage_pos(storage_pos),
+                m_storage_neg(storage_neg) {
+            }
+
+            NodeLocationsForWays(const NodeLocationsForWays&) = delete;
+            NodeLocationsForWays& operator=(const NodeLocationsForWays&) = delete;
+
+            NodeLocationsForWays(NodeLocationsForWays&&) = default;
+            NodeLocationsForWays& operator=(NodeLocationsForWays&&) = default;
+
+            ~NodeLocationsForWays() noexcept = default;
+
+            void ignore_errors() {
+                m_ignore_errors = true;
+            }
+
+            /**
+             * Store the location of the node in the storage.
+             */
+            void node(const osmium::Node& node) {
+                m_must_sort = true;
+                const osmium::object_id_type id = node.id();
+                if (id >= 0) {
+                    m_storage_pos.set(static_cast<osmium::unsigned_object_id_type>( id), node.location());
+                } else {
+                    m_storage_neg.set(static_cast<osmium::unsigned_object_id_type>(-id), node.location());
+                }
+            }
+
+            /**
+             * Get location of node with given id.
+             */
+            osmium::Location get_node_location(const osmium::object_id_type id) const {
+                if (id >= 0) {
+                    return m_storage_pos.get(static_cast<osmium::unsigned_object_id_type>( id));
+                } else {
+                    return m_storage_neg.get(static_cast<osmium::unsigned_object_id_type>(-id));
+                }
+            }
+
+            /**
+             * Retrieve locations of all nodes in the way from storage and add
+             * them to the way object.
+             */
+            void way(osmium::Way& way) {
+                if (m_must_sort) {
+                    m_storage_pos.sort();
+                    m_storage_neg.sort();
+                    m_must_sort = false;
+                }
+                bool error = false;
+                for (auto& node_ref : way.nodes()) {
+                    try {
+                        node_ref.set_location(get_node_location(node_ref.ref()));
+                        if (!node_ref.location()) {
+                            error = true;
+                        }
+                    } catch (osmium::not_found&) {
+                        error = true;
+                    }
+                }
+                if (error && !m_ignore_errors) {
+                    throw osmium::not_found("location for one or more nodes not found in node location index");
+                }
+            }
+
+            /**
+             * Call clear on the location indexes. Makes the
+             * NodeLocationsForWays handler unusable. Used to explicitly free
+             * memory if thats needed.
+             */
+            void clear() {
+                m_storage_pos.clear();
+                m_storage_neg.clear();
+            }
+
+        }; // class NodeLocationsForWays
+
+    } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP
diff --git a/contrib/libosmium/osmium/handler/object_relations.hpp b/contrib/libosmium/osmium/handler/object_relations.hpp
new file mode 100644
index 0000000..dc4aa45
--- /dev/null
+++ b/contrib/libosmium/osmium/handler/object_relations.hpp
@@ -0,0 +1,106 @@
+#ifndef OSMIUM_HANDLER_OBJECT_RELATIONS_HPP
+#define OSMIUM_HANDLER_OBJECT_RELATIONS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/handler.hpp>
+#include <osmium/index/multimap.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+    namespace handler {
+
+        /**
+         *
+         * Note: This handler will only work if either all object IDs are
+         *       positive or all object IDs are negative.
+         */
+        class ObjectRelations : public osmium::handler::Handler {
+
+            typedef osmium::index::multimap::Multimap<unsigned_object_id_type, unsigned_object_id_type> index_type;
+
+            index_type& m_index_n2w;
+            index_type& m_index_n2r;
+            index_type& m_index_w2r;
+            index_type& m_index_r2r;
+
+        public:
+
+            explicit ObjectRelations(index_type& n2w, index_type& n2r, index_type& w2r, index_type& r2r) :
+                m_index_n2w(n2w),
+                m_index_n2r(n2r),
+                m_index_w2r(w2r),
+                m_index_r2r(r2r) {
+            }
+
+            ObjectRelations(const ObjectRelations&) = delete;
+            ObjectRelations& operator=(const ObjectRelations&) = delete;
+
+            ~ObjectRelations() noexcept = default;
+
+            void way(const osmium::Way& way) {
+                for (const auto& node_ref : way.nodes()) {
+                    m_index_n2w.set(node_ref.positive_ref(), way.positive_id());
+                }
+            }
+
+            void relation(const osmium::Relation& relation) {
+                for (const auto& member : relation.members()) {
+                    switch (member.type()) {
+                        case osmium::item_type::node:
+                            m_index_n2r.set(member.positive_ref(), relation.positive_id());
+                            break;
+                        case osmium::item_type::way:
+                            m_index_w2r.set(member.positive_ref(), relation.positive_id());
+                            break;
+                        case osmium::item_type::relation:
+                            m_index_r2r.set(member.positive_ref(), relation.positive_id());
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            }
+
+        }; // class ObjectRelations
+
+    } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_OBJECT_RELATIONS_HPP
diff --git a/contrib/libosmium/osmium/index/bool_vector.hpp b/contrib/libosmium/osmium/index/bool_vector.hpp
new file mode 100644
index 0000000..04850a5
--- /dev/null
+++ b/contrib/libosmium/osmium/index/bool_vector.hpp
@@ -0,0 +1,85 @@
+#ifndef OSMIUM_INDEX_BOOL_VECTOR_HPP
+#define OSMIUM_INDEX_BOOL_VECTOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <type_traits>
+#include <vector>
+
+namespace osmium {
+
+    namespace index {
+
+        /**
+         * Index storing one bit for each Id. The index automatically scales
+         * with the Ids stored. Default value is 'false'. Storage uses
+         * std::vector<bool> and needs a minimum of memory if the Ids are
+         * dense.
+         */
+        template <typename T>
+        class BoolVector {
+
+            static_assert(std::is_unsigned<T>::value, "Needs unsigned type");
+
+            std::vector<bool> m_bits;
+
+        public:
+
+            BoolVector() = default;
+
+            BoolVector(const BoolVector&) = default;
+            BoolVector(BoolVector&&) = default;
+            BoolVector& operator=(const BoolVector&) = default;
+            BoolVector& operator=(BoolVector&&) = default;
+
+            ~BoolVector() noexcept = default;
+
+            void set(T id, bool value = true) {
+                if (m_bits.size() <= id) {
+                    m_bits.resize(id + 1024 * 1024);
+                }
+
+                m_bits[id] = value;
+            }
+
+            bool get(T id) const {
+                return id < m_bits.size() && m_bits[id];
+            }
+
+        }; // class BoolVector
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_BOOL_VECTOR_HPP
diff --git a/contrib/libosmium/osmium/index/detail/create_map_with_fd.hpp b/contrib/libosmium/osmium/index/detail/create_map_with_fd.hpp
new file mode 100644
index 0000000..5eb6cd0
--- /dev/null
+++ b/contrib/libosmium/osmium/index/detail/create_map_with_fd.hpp
@@ -0,0 +1,71 @@
+#ifndef OSMIUM_INDEX_DETAIL_CREATE_MAP_WITH_FD_HPP
+#define OSMIUM_INDEX_DETAIL_CREATE_MAP_WITH_FD_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cerrno>
+#include <cstring>
+#include <fcntl.h>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace detail {
+
+            template <typename T>
+            inline T* create_map_with_fd(const std::vector<std::string>& config) {
+                if (config.size() == 1) {
+                    return new T();
+                } else {
+                    assert(config.size() > 1);
+                    const std::string& filename = config[1];
+                    int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644);
+                    if (fd == -1) {
+                        throw std::runtime_error(std::string("can't open file '") + filename + "': " + strerror(errno));
+                    }
+                    return new T(fd);
+                }
+            }
+
+        } // namespace detail
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_DETAIL_CREATE_MAP_WITH_FD_HPP
diff --git a/contrib/libosmium/osmium/index/detail/mmap_vector_anon.hpp b/contrib/libosmium/osmium/index/detail/mmap_vector_anon.hpp
new file mode 100644
index 0000000..12a1803
--- /dev/null
+++ b/contrib/libosmium/osmium/index/detail/mmap_vector_anon.hpp
@@ -0,0 +1,67 @@
+#ifndef OSMIUM_INDEX_DETAIL_MMAP_VECTOR_ANON_HPP
+#define OSMIUM_INDEX_DETAIL_MMAP_VECTOR_ANON_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#ifdef __linux__
+
+#include <osmium/index/detail/mmap_vector_base.hpp>
+
+namespace osmium {
+
+    namespace detail {
+
+        /**
+         * This class looks and behaves like STL vector, but uses mmap
+         * internally.
+         */
+        template <typename T>
+        class mmap_vector_anon : public mmap_vector_base<T> {
+
+        public:
+
+            mmap_vector_anon() :
+                mmap_vector_base<T>() {
+            }
+
+            ~mmap_vector_anon() noexcept = default;
+
+        }; // class mmap_vector_anon
+
+    } // namespace detail
+
+} // namespace osmium
+
+#endif // __linux__
+
+#endif // OSMIUM_INDEX_DETAIL_MMAP_VECTOR_ANON_HPP
diff --git a/contrib/libosmium/osmium/index/detail/mmap_vector_base.hpp b/contrib/libosmium/osmium/index/detail/mmap_vector_base.hpp
new file mode 100644
index 0000000..e5f28e9
--- /dev/null
+++ b/contrib/libosmium/osmium/index/detail/mmap_vector_base.hpp
@@ -0,0 +1,180 @@
+#ifndef OSMIUM_INDEX_DETAIL_MMAP_VECTOR_BASE_HPP
+#define OSMIUM_INDEX_DETAIL_MMAP_VECTOR_BASE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <new> // IWYU pragma: keep
+#include <stdexcept>
+
+#include <osmium/util/memory_mapping.hpp>
+
+namespace osmium {
+
+    namespace detail {
+
+        constexpr size_t mmap_vector_size_increment = 1024 * 1024;
+
+        /**
+         * This is a base class for implementing classes that look like
+         * STL vector but use mmap internally. Do not use this class itself,
+         * use the derived classes mmap_vector_anon or mmap_vector_file.
+         */
+        template <typename T>
+        class mmap_vector_base {
+
+        protected:
+
+            size_t m_size;
+            osmium::util::TypedMemoryMapping<T> m_mapping;
+
+        public:
+
+            mmap_vector_base(int fd, size_t capacity, size_t size = 0) :
+                m_size(size),
+                m_mapping(capacity, osmium::util::MemoryMapping::mapping_mode::write_shared, fd) {
+            }
+
+            explicit mmap_vector_base(size_t capacity = mmap_vector_size_increment) :
+                m_size(0),
+                m_mapping(capacity) {
+            }
+
+            ~mmap_vector_base() noexcept = default;
+
+            typedef T value_type;
+            typedef T& reference;
+            typedef const T& const_reference;
+            typedef T* pointer;
+            typedef const T* const_pointer;
+            typedef T* iterator;
+            typedef const T* const_iterator;
+
+            void close() {
+                m_mapping.unmap();
+            }
+
+            size_t capacity() const noexcept {
+                return m_mapping.size();
+            }
+
+            size_t size() const noexcept {
+                return m_size;
+            }
+
+            bool empty() const noexcept {
+                return m_size == 0;
+            }
+
+            const T* data() const {
+                return m_mapping.begin();
+            }
+
+            T* data() {
+                return m_mapping.begin();
+            }
+
+            T& operator[](size_t n) {
+                return data()[n];
+            }
+
+            T at(size_t n) const {
+                if (n >= m_size) {
+                    throw std::out_of_range("out of range");
+                }
+                return data()[n];
+            }
+
+            void clear() noexcept {
+                m_size = 0;
+            }
+
+            void shrink_to_fit() {
+                // XXX do something here
+            }
+
+            void push_back(const T& value) {
+                if (m_size >= capacity()) {
+                    resize(m_size+1);
+                }
+                data()[m_size] = value;
+                ++m_size;
+            }
+
+            void reserve(size_t new_capacity) {
+                if (new_capacity > capacity()) {
+                    m_mapping.resize(new_capacity);
+                }
+            }
+
+            void resize(size_t new_size) {
+                if (new_size > capacity()) {
+                    reserve(new_size + osmium::detail::mmap_vector_size_increment);
+                }
+                if (new_size > size()) {
+                    new (data() + size()) T[new_size - size()];
+                }
+                m_size = new_size;
+            }
+
+            iterator begin() noexcept {
+                return data();
+            }
+
+            iterator end() noexcept {
+                return data() + m_size;
+            }
+
+            const_iterator begin() const noexcept {
+                return data();
+            }
+
+            const_iterator end() const noexcept {
+                return data() + m_size;
+            }
+
+            const_iterator cbegin() const noexcept {
+                return data();
+            }
+
+            const_iterator cend() const noexcept {
+                return data() + m_size;
+            }
+
+        }; // class mmap_vector_base
+
+    } // namespace detail
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_DETAIL_MMAP_VECTOR_BASE_HPP
diff --git a/contrib/libosmium/osmium/index/detail/mmap_vector_file.hpp b/contrib/libosmium/osmium/index/detail/mmap_vector_file.hpp
new file mode 100644
index 0000000..54ef513
--- /dev/null
+++ b/contrib/libosmium/osmium/index/detail/mmap_vector_file.hpp
@@ -0,0 +1,74 @@
+#ifndef OSMIUM_INDEX_DETAIL_MMAP_VECTOR_FILE_HPP
+#define OSMIUM_INDEX_DETAIL_MMAP_VECTOR_FILE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/index/detail/mmap_vector_base.hpp>
+#include <osmium/index/detail/tmpfile.hpp>
+#include <osmium/util/file.hpp>
+
+namespace osmium {
+
+    namespace detail {
+
+        /**
+         * This class looks and behaves like STL vector, but mmap's a file
+         * internally.
+         */
+        template <typename T>
+        class mmap_vector_file : public mmap_vector_base<T> {
+
+        public:
+
+            mmap_vector_file() :
+                mmap_vector_base<T>(
+                    osmium::detail::create_tmp_file(),
+                    osmium::detail::mmap_vector_size_increment) {
+            }
+
+            explicit mmap_vector_file(int fd) :
+                mmap_vector_base<T>(
+                    fd,
+                    osmium::util::file_size(fd) / sizeof(T),
+                    osmium::util::file_size(fd) / sizeof(T)) {
+            }
+
+            ~mmap_vector_file() noexcept = default;
+
+        }; // class mmap_vector_file
+
+    } // namespace detail
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_DETAIL_MMAP_VECTOR_FILE_HPP
diff --git a/contrib/libosmium/osmium/index/detail/tmpfile.hpp b/contrib/libosmium/osmium/index/detail/tmpfile.hpp
new file mode 100644
index 0000000..06cab65
--- /dev/null
+++ b/contrib/libosmium/osmium/index/detail/tmpfile.hpp
@@ -0,0 +1,62 @@
+#ifndef OSMIUM_INDEX_DETAIL_TMPFILE_HPP
+#define OSMIUM_INDEX_DETAIL_TMPFILE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cerrno>
+#include <cstdio>
+#include <system_error>
+
+namespace osmium {
+
+    namespace detail {
+
+        /**
+         * Create and open a temporary file. It is removed after opening.
+         *
+         * @returns File descriptor of temporary file.
+         * @throws std::system_error if something went wrong.
+         */
+        inline int create_tmp_file() {
+            FILE* file = ::tmpfile();
+            if (!file) {
+                throw std::system_error(errno, std::system_category(), "tempfile failed");
+            }
+            return fileno(file);
+        }
+
+    } // namespace detail
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_DETAIL_TMPFILE_HPP
diff --git a/contrib/libosmium/osmium/index/detail/vector_map.hpp b/contrib/libosmium/osmium/index/detail/vector_map.hpp
new file mode 100644
index 0000000..48b0f62
--- /dev/null
+++ b/contrib/libosmium/osmium/index/detail/vector_map.hpp
@@ -0,0 +1,246 @@
+#ifndef OSMIUM_INDEX_DETAIL_VECTOR_MAP_HPP
+#define OSMIUM_INDEX_DETAIL_VECTOR_MAP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <stdexcept>
+#include <utility>
+
+#include <osmium/index/index.hpp>
+#include <osmium/index/map.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            template <typename TVector, typename TId, typename TValue>
+            class VectorBasedDenseMap : public Map<TId, TValue> {
+
+                TVector m_vector;
+
+            public:
+
+                typedef TValue element_type;
+                typedef TVector vector_type;
+                typedef typename vector_type::iterator iterator;
+                typedef typename vector_type::const_iterator const_iterator;
+
+                VectorBasedDenseMap() :
+                    m_vector() {
+                }
+
+                explicit VectorBasedDenseMap(int fd) :
+                    m_vector(fd) {
+                }
+
+                ~VectorBasedDenseMap() noexcept = default;
+
+                void reserve(const size_t size) override final {
+                    m_vector.reserve(size);
+                }
+
+                void set(const TId id, const TValue value) override final {
+                    if (size() <= id) {
+                        m_vector.resize(id+1);
+                    }
+                    m_vector[id] = value;
+                }
+
+                const TValue get(const TId id) const override final {
+                    try {
+                        const TValue& value = m_vector.at(id);
+                        if (value == osmium::index::empty_value<TValue>()) {
+                            not_found_error(id);
+                        }
+                        return value;
+                    } catch (std::out_of_range&) {
+                        not_found_error(id);
+                    }
+                }
+
+                size_t size() const override final {
+                    return m_vector.size();
+                }
+
+                size_t byte_size() const {
+                    return m_vector.size() * sizeof(element_type);
+                }
+
+                size_t used_memory() const override final {
+                    return sizeof(TValue) * size();
+                }
+
+                void clear() override final {
+                    m_vector.clear();
+                    m_vector.shrink_to_fit();
+                }
+
+                void dump_as_array(const int fd) override final {
+                    osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
+                }
+
+                iterator begin() {
+                    return m_vector.begin();
+                }
+
+                iterator end() {
+                    return m_vector.end();
+                }
+
+                const_iterator cbegin() const {
+                    return m_vector.cbegin();
+                }
+
+                const_iterator cend() const {
+                    return m_vector.cend();
+                }
+
+                const_iterator begin() const {
+                    return m_vector.cbegin();
+                }
+
+                const_iterator end() const {
+                    return m_vector.cend();
+                }
+
+            }; // class VectorBasedDenseMap
+
+
+            template <typename TId, typename TValue, template<typename...> class TVector>
+            class VectorBasedSparseMap : public Map<TId, TValue> {
+
+            public:
+
+                typedef typename std::pair<TId, TValue> element_type;
+                typedef TVector<element_type> vector_type;
+                typedef typename vector_type::iterator iterator;
+                typedef typename vector_type::const_iterator const_iterator;
+
+            private:
+
+                vector_type m_vector;
+
+            public:
+
+                VectorBasedSparseMap() :
+                    m_vector() {
+                }
+
+                VectorBasedSparseMap(int fd) :
+                    m_vector(fd) {
+                }
+
+                ~VectorBasedSparseMap() override final = default;
+
+                void set(const TId id, const TValue value) override final {
+                    m_vector.push_back(element_type(id, value));
+                }
+
+                const TValue get(const TId id) const override final {
+                    const element_type element {
+                        id,
+                        osmium::index::empty_value<TValue>()
+                    };
+                    const auto result = std::lower_bound(m_vector.begin(), m_vector.end(), element, [](const element_type& a, const element_type& b) {
+                        return a.first < b.first;
+                    });
+                    if (result == m_vector.end() || result->first != id) {
+                        not_found_error(id);
+                    } else {
+                        return result->second;
+                    }
+                }
+
+                size_t size() const override final {
+                    return m_vector.size();
+                }
+
+                size_t byte_size() const {
+                    return m_vector.size() * sizeof(element_type);
+                }
+
+                size_t used_memory() const override final {
+                    return sizeof(element_type) * size();
+                }
+
+                void clear() override final {
+                    m_vector.clear();
+                    m_vector.shrink_to_fit();
+                }
+
+                void sort() override final {
+                    std::sort(m_vector.begin(), m_vector.end());
+                }
+
+                void dump_as_list(const int fd) override final {
+                    osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
+                }
+
+                iterator begin() {
+                    return m_vector.begin();
+                }
+
+                iterator end() {
+                    return m_vector.end();
+                }
+
+                const_iterator cbegin() const {
+                    return m_vector.cbegin();
+                }
+
+                const_iterator cend() const {
+                    return m_vector.cend();
+                }
+
+                const_iterator begin() const {
+                    return m_vector.cbegin();
+                }
+
+                const_iterator end() const {
+                    return m_vector.cend();
+                }
+
+            }; // class VectorBasedSparseMap
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_DETAIL_VECTOR_MAP_HPP
diff --git a/contrib/libosmium/osmium/index/detail/vector_multimap.hpp b/contrib/libosmium/osmium/index/detail/vector_multimap.hpp
new file mode 100644
index 0000000..dc2e15a
--- /dev/null
+++ b/contrib/libosmium/osmium/index/detail/vector_multimap.hpp
@@ -0,0 +1,186 @@
+#ifndef OSMIUM_INDEX_DETAIL_VECTOR_MULTIMAP_HPP
+#define OSMIUM_INDEX_DETAIL_VECTOR_MULTIMAP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <utility>
+
+#include <osmium/index/index.hpp>
+#include <osmium/index/multimap.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace multimap {
+
+            template <typename TId, typename TValue, template<typename...> class TVector>
+            class VectorBasedSparseMultimap : public Multimap<TId, TValue> {
+
+            public:
+
+                typedef typename std::pair<TId, TValue> element_type;
+                typedef TVector<element_type> vector_type;
+                typedef typename vector_type::iterator iterator;
+                typedef typename vector_type::const_iterator const_iterator;
+
+            private:
+
+                vector_type m_vector;
+
+                static bool is_removed(element_type& element) {
+                    return element.second == osmium::index::empty_value<TValue>();
+                }
+
+            public:
+
+                VectorBasedSparseMultimap() :
+                    m_vector() {
+                }
+
+                explicit VectorBasedSparseMultimap(int fd) :
+                    m_vector(fd) {
+                }
+
+                ~VectorBasedSparseMultimap() noexcept = default;
+
+                void set(const TId id, const TValue value) override final {
+                    m_vector.push_back(element_type(id, value));
+                }
+
+                void unsorted_set(const TId id, const TValue value) {
+                    m_vector.push_back(element_type(id, value));
+                }
+
+                std::pair<iterator, iterator> get_all(const TId id) {
+                    const element_type element {
+                        id,
+                        osmium::index::empty_value<TValue>()
+                    };
+                    return std::equal_range(m_vector.begin(), m_vector.end(), element, [](const element_type& a, const element_type& b) {
+                        return a.first < b.first;
+                    });
+                }
+
+                std::pair<const_iterator, const_iterator> get_all(const TId id) const {
+                    const element_type element {
+                        id,
+                        osmium::index::empty_value<TValue>()
+                    };
+                    return std::equal_range(m_vector.cbegin(), m_vector.cend(), element, [](const element_type& a, const element_type& b) {
+                        return a.first < b.first;
+                    });
+                }
+
+                size_t size() const override final {
+                    return m_vector.size();
+                }
+
+                size_t byte_size() const {
+                    return m_vector.size() * sizeof(element_type);
+                }
+
+                size_t used_memory() const override final {
+                    return sizeof(element_type) * size();
+                }
+
+                void clear() override final {
+                    m_vector.clear();
+                    m_vector.shrink_to_fit();
+                }
+
+                void sort() override final {
+                    std::sort(m_vector.begin(), m_vector.end());
+                }
+
+                void remove(const TId id, const TValue value) {
+                    auto r = get_all(id);
+                    for (auto it = r.first; it != r.second; ++it) {
+                        if (it->second == value) {
+                            it->second = 0;
+                            return;
+                        }
+                    }
+                }
+
+                void consolidate() {
+                    std::sort(m_vector.begin(), m_vector.end());
+                }
+
+                void erase_removed() {
+                    m_vector.erase(
+                        std::remove_if(m_vector.begin(), m_vector.end(), is_removed),
+                        m_vector.end()
+                    );
+                }
+
+                void dump_as_list(const int fd) override final {
+                    osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
+                }
+
+                iterator begin() {
+                    return m_vector.begin();
+                }
+
+                iterator end() {
+                    return m_vector.end();
+                }
+
+                const_iterator cbegin() const {
+                    return m_vector.cbegin();
+                }
+
+                const_iterator cend() const {
+                    return m_vector.cend();
+                }
+
+                const_iterator begin() const {
+                    return m_vector.cbegin();
+                }
+
+                const_iterator end() const {
+                    return m_vector.cend();
+                }
+
+            }; // class VectorBasedSparseMultimap
+
+        } // namespace multimap
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_DETAIL_VECTOR_MULTIMAP_HPP
diff --git a/contrib/libosmium/osmium/index/index.hpp b/contrib/libosmium/osmium/index/index.hpp
new file mode 100644
index 0000000..f415192
--- /dev/null
+++ b/contrib/libosmium/osmium/index/index.hpp
@@ -0,0 +1,100 @@
+#ifndef OSMIUM_INDEX_INDEX_HPP
+#define OSMIUM_INDEX_INDEX_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <limits>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception signaling that an element could not be
+     * found in an index.
+     */
+    struct not_found : public std::runtime_error {
+
+        not_found(const std::string& what) :
+            std::runtime_error(what) {
+        }
+
+        not_found(const char* what) :
+            std::runtime_error(what) {
+        }
+
+    }; // struct not_found
+
+    /**
+     * @brief Indexing of OSM data, Locations, etc.
+     */
+    namespace index {
+
+        template <typename TKey>
+        OSMIUM_NORETURN void not_found_error(TKey key) {
+            std::stringstream s;
+            s << "id " << key << " not found";
+            throw not_found(s.str());
+        }
+
+        /**
+         * Some of the index classes need an "empty" value that can
+         * never appear in real data. This function must return this
+         * empty value for any class used as a value in an index.
+         * The default implementation returns a default constructed
+         * object, but it can be specialized.
+         */
+        template <typename T>
+        inline constexpr T empty_value() {
+            return T{};
+        }
+
+        /**
+         * The size_t value in indexes is usually used for offsets
+         * into a buffer or file. It is unlikely that we ever need
+         * the full range, so the max value is a good "empty" value.
+         */
+        template <>
+        inline OSMIUM_CONSTEXPR size_t empty_value<size_t>() {
+            return std::numeric_limits<size_t>::max();
+        }
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_INDEX_HPP
diff --git a/contrib/libosmium/osmium/index/map.hpp b/contrib/libosmium/osmium/index/map.hpp
new file mode 100644
index 0000000..68a9c20
--- /dev/null
+++ b/contrib/libosmium/osmium/index/map.hpp
@@ -0,0 +1,275 @@
+#ifndef OSMIUM_INDEX_MAP_HPP
+#define OSMIUM_INDEX_MAP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <functional>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <osmium/util/compatibility.hpp>
+#include <osmium/util/string.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        /**
+         * @brief Key-value containers with unique integer values for a key
+         */
+        namespace map {
+
+            /**
+             * This abstract class defines an interface to storage classes
+             * intended for storing small pieces of data (such as coordinates)
+             * indexed by a positive integer (such as an object ID). The
+             * storage must be very space efficient and able to scale to billions
+             * of objects.
+             *
+             * Subclasses have different implementations that store the
+             * data in different ways in memory and/or on disk. Some storage
+             * classes are better suited when working with the whole planet,
+             * some are better for data extracts.
+             *
+             * Note that these classes are not required to track "empty" fields.
+             * When reading data you have to be sure you have put something in
+             * there before.
+             *
+             * A typical use for this and derived classes is storage of node
+             * locations indexed by node ID. These indexes will only work
+             * on 64 bit systems if used in this case. 32 bit systems just
+             * can't address that much memory!
+             *
+             * @tparam TId Id type, usually osmium::unsigned_object_id_type,
+             *             must be an unsigned integral type.
+             * @tparam TValue Value type, usually osmium::Location or size_t.
+             *                Copied by value, so should be "small" type.
+             */
+            template <typename TId, typename TValue>
+            class Map {
+
+                static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value,
+                              "TId template parameter for class Map must be unsigned integral type");
+
+                Map(const Map&) = delete;
+                Map& operator=(const Map&) = delete;
+
+            protected:
+
+                Map(Map&&) = default;
+                Map& operator=(Map&&) = default;
+
+            public:
+
+                /// The "key" type, usually osmium::unsigned_object_id_type.
+                typedef TId key_type;
+
+                /// The "value" type, usually a Location or size_t.
+                typedef TValue value_type;
+
+                Map() = default;
+
+                virtual ~Map() noexcept = default;
+
+                virtual void reserve(const size_t) {
+                    // default implementation is empty
+                }
+
+                /// Set the field with id to value.
+                virtual void set(const TId id, const TValue value) = 0;
+
+                /// Retrieve value by id. Does not check for overflow or empty fields.
+                virtual const TValue get(const TId id) const = 0;
+
+                /**
+                 * Get the approximate number of items in the storage. The storage
+                 * might allocate memory in blocks, so this size might not be
+                 * accurate. You can not use this to find out how much memory the
+                 * storage uses. Use used_memory() for that.
+                 */
+                virtual size_t size() const = 0;
+
+                /**
+                 * Get the memory used for this storage in bytes. Note that this
+                 * is not necessarily entirely accurate but an approximation.
+                 * For storage classes that store the data in memory, this is
+                 * the main memory used, for storage classes storing data on disk
+                 * this is the memory used on disk.
+                 */
+                virtual size_t used_memory() const = 0;
+
+                /**
+                 * Clear memory used for this storage. After this you can not
+                 * use the storage container any more.
+                 */
+                virtual void clear() = 0;
+
+                /**
+                 * Sort data in map. Call this after writing all data and
+                 * before reading. Not all implementations need this.
+                 */
+                virtual void sort() {
+                    // default implementation is empty
+                }
+
+                // This function could usually be const in derived classes,
+                // but not always. It could, for instance, sort internal data.
+                // This is why it is not declared const here.
+                virtual void dump_as_list(const int /*fd*/) {
+                    throw std::runtime_error("can't dump as list");
+                }
+
+                // This function could usually be const in derived classes,
+                // but not always. It could, for instance, sort internal data.
+                // This is why it is not declared const here.
+                virtual void dump_as_array(const int /*fd*/) {
+                    throw std::runtime_error("can't dump as array");
+                }
+
+            }; // class Map
+
+        } // namespace map
+
+        template <typename TId, typename TValue>
+        class MapFactory {
+
+        public:
+
+            typedef TId id_type;
+            typedef TValue value_type;
+            typedef osmium::index::map::Map<id_type, value_type> map_type;
+            typedef std::function<map_type*(const std::vector<std::string>&)> create_map_func;
+
+        private:
+
+            std::map<const std::string, create_map_func> m_callbacks;
+
+            MapFactory() = default;
+
+            MapFactory(const MapFactory&) = delete;
+            MapFactory& operator=(const MapFactory&) = delete;
+
+            MapFactory(MapFactory&&) = delete;
+            MapFactory& operator=(MapFactory&&) = delete;
+
+            OSMIUM_NORETURN static void error(const std::string& map_type_name) {
+                std::string error_message {"Support for map type '"};
+                error_message += map_type_name;
+                error_message += "' not compiled into this binary.";
+                throw std::runtime_error(error_message);
+            }
+
+        public:
+
+            static MapFactory<id_type, value_type>& instance() {
+                static MapFactory<id_type, value_type> factory;
+                return factory;
+            }
+
+            bool register_map(const std::string& map_type_name, create_map_func func) {
+                return m_callbacks.emplace(map_type_name, func).second;
+            }
+
+            bool has_map_type(const std::string& map_type_name) const {
+                return m_callbacks.count(map_type_name);
+            }
+
+            std::vector<std::string> map_types() const {
+                std::vector<std::string> result;
+
+                for (const auto& cb : m_callbacks) {
+                    result.push_back(cb.first);
+                }
+
+                std::sort(result.begin(), result.end());
+
+                return result;
+            }
+
+            std::unique_ptr<map_type> create_map(const std::string& config_string) const {
+                std::vector<std::string> config = osmium::split_string(config_string, ',');
+
+                if (config.empty()) {
+                    throw std::runtime_error("Need non-empty map type name.");
+                }
+
+                auto it = m_callbacks.find(config[0]);
+                if (it != m_callbacks.end()) {
+                    return std::unique_ptr<map_type>((it->second)(config));
+                }
+
+                error(config[0]);
+            }
+
+        }; // class MapFactory
+
+        namespace map {
+
+            template <typename TId, typename TValue, template<typename, typename> class TMap>
+            struct create_map {
+                TMap<TId, TValue>* operator()(const std::vector<std::string>&) {
+                    return new TMap<TId, TValue>();
+                }
+            };
+
+        } // namespace map
+
+        template <typename TId, typename TValue, template<typename, typename> class TMap>
+        inline bool register_map(const std::string& name) {
+            return osmium::index::MapFactory<TId, TValue>::instance().register_map(name, [](const std::vector<std::string>& config) {
+                return map::create_map<TId, TValue, TMap>()(config);
+            });
+        }
+
+#define OSMIUM_CONCATENATE_DETAIL_(x, y) x##y
+#define OSMIUM_CONCATENATE_(x, y) OSMIUM_CONCATENATE_DETAIL_(x, y)
+
+#define REGISTER_MAP(id, value, klass, name) \
+namespace osmium { namespace index { namespace detail { \
+    const bool OSMIUM_CONCATENATE_(registered_, name) = osmium::index::register_map<id, value, klass>(#name); \
+    inline bool OSMIUM_CONCATENATE_(get_registered_, name)() noexcept { \
+        return OSMIUM_CONCATENATE_(registered_, name); \
+    } \
+} } }
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_HPP
diff --git a/contrib/libosmium/osmium/index/map/all.hpp b/contrib/libosmium/osmium/index/map/all.hpp
new file mode 100644
index 0000000..9ffadc0
--- /dev/null
+++ b/contrib/libosmium/osmium/index/map/all.hpp
@@ -0,0 +1,46 @@
+#ifndef OSMIUM_INDEX_MAP_ALL_HPP
+#define OSMIUM_INDEX_MAP_ALL_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/index/map/dense_file_array.hpp>  // IWYU pragma: keep
+#include <osmium/index/map/dense_mem_array.hpp>   // IWYU pragma: keep
+#include <osmium/index/map/dense_mmap_array.hpp>  // IWYU pragma: keep
+#include <osmium/index/map/dummy.hpp>             // IWYU pragma: keep
+#include <osmium/index/map/sparse_file_array.hpp> // IWYU pragma: keep
+#include <osmium/index/map/sparse_mem_array.hpp>  // IWYU pragma: keep
+#include <osmium/index/map/sparse_mem_map.hpp>    // IWYU pragma: keep
+#include <osmium/index/map/sparse_mem_table.hpp>  // IWYU pragma: keep
+#include <osmium/index/map/sparse_mmap_array.hpp> // IWYU pragma: keep
+
+#endif // OSMIUM_INDEX_MAP_ALL_HPP
diff --git a/contrib/libosmium/osmium/index/map/dense_file_array.hpp b/contrib/libosmium/osmium/index/map/dense_file_array.hpp
new file mode 100644
index 0000000..d209a87
--- /dev/null
+++ b/contrib/libosmium/osmium/index/map/dense_file_array.hpp
@@ -0,0 +1,67 @@
+#ifndef OSMIUM_INDEX_MAP_DENSE_FILE_ARRAY_HPP
+#define OSMIUM_INDEX_MAP_DENSE_FILE_ARRAY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <string>
+#include <vector>
+
+#include <osmium/index/detail/mmap_vector_file.hpp>
+#include <osmium/index/detail/vector_map.hpp>
+#include <osmium/index/detail/create_map_with_fd.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_DENSE_FILE_ARRAY
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            template <typename TId, typename TValue>
+            using DenseFileArray = VectorBasedDenseMap<osmium::detail::mmap_vector_file<TValue>, TId, TValue>;
+
+            template <typename TId, typename TValue>
+            struct create_map<TId, TValue, DenseFileArray> {
+                DenseFileArray<TId, TValue>* operator()(const std::vector<std::string>& config) {
+                    return osmium::index::detail::create_map_with_fd<DenseFileArray<TId, TValue>>(config);
+                }
+            };
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_DENSE_FILE_ARRAY_HPP
diff --git a/contrib/libosmium/osmium/index/map/dense_mem_array.hpp b/contrib/libosmium/osmium/index/map/dense_mem_array.hpp
new file mode 100644
index 0000000..b45eec4
--- /dev/null
+++ b/contrib/libosmium/osmium/index/map/dense_mem_array.hpp
@@ -0,0 +1,57 @@
+#ifndef OSMIUM_INDEX_MAP_DENSE_MEM_ARRAY_HPP
+#define OSMIUM_INDEX_MAP_DENSE_MEM_ARRAY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <vector>
+
+#include <osmium/index/detail/vector_map.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_DENSE_MEM_ARRAY
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            template <typename TId, typename TValue>
+            using DenseMemArray = VectorBasedDenseMap<std::vector<TValue>, TId, TValue>;
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_DENSE_MEM_ARRAY_HPP
diff --git a/contrib/libosmium/osmium/index/map/dense_mmap_array.hpp b/contrib/libosmium/osmium/index/map/dense_mmap_array.hpp
new file mode 100644
index 0000000..a912aeb
--- /dev/null
+++ b/contrib/libosmium/osmium/index/map/dense_mmap_array.hpp
@@ -0,0 +1,60 @@
+#ifndef OSMIUM_INDEX_MAP_DENSE_MMAP_ARRAY_HPP
+#define OSMIUM_INDEX_MAP_DENSE_MMAP_ARRAY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#ifdef __linux__
+
+#include <osmium/index/detail/mmap_vector_anon.hpp> // IWYU pragma: keep
+#include <osmium/index/detail/vector_map.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_DENSE_MMAP_ARRAY
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            template <typename TId, typename TValue>
+            using DenseMmapArray = VectorBasedDenseMap<osmium::detail::mmap_vector_anon<TValue>, TId, TValue>;
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // __linux__
+
+#endif // OSMIUM_INDEX_MAP_DENSE_MMAP_ARRAY_HPP
diff --git a/contrib/libosmium/osmium/index/map/dummy.hpp b/contrib/libosmium/osmium/index/map/dummy.hpp
new file mode 100644
index 0000000..5b471df
--- /dev/null
+++ b/contrib/libosmium/osmium/index/map/dummy.hpp
@@ -0,0 +1,88 @@
+#ifndef OSMIUM_INDEX_MAP_DUMMY_HPP
+#define OSMIUM_INDEX_MAP_DUMMY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+
+#include <osmium/index/index.hpp>
+#include <osmium/index/map.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            /**
+             * Pseudo map.
+             * Use this class if you don't need a map, but you
+             * need an object that behaves like one.
+             */
+            template <typename TId, typename TValue>
+            class Dummy : public osmium::index::map::Map<TId, TValue> {
+
+            public:
+
+                Dummy() = default;
+
+                ~Dummy() noexcept override final = default;
+
+                void set(const TId, const TValue) override final {
+                    // intentionally left blank
+                }
+
+                const TValue get(const TId id) const override final {
+                    not_found_error(id);
+                }
+
+                size_t size() const override final {
+                    return 0;
+                }
+
+                size_t used_memory() const override final {
+                    return 0;
+                }
+
+                void clear() override final {
+                }
+
+            }; // class Dummy
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_DUMMY_HPP
diff --git a/contrib/libosmium/osmium/index/map/sparse_file_array.hpp b/contrib/libosmium/osmium/index/map/sparse_file_array.hpp
new file mode 100644
index 0000000..2ba9315
--- /dev/null
+++ b/contrib/libosmium/osmium/index/map/sparse_file_array.hpp
@@ -0,0 +1,67 @@
+#ifndef OSMIUM_INDEX_MAP_SPARSE_FILE_ARRAY_HPP
+#define OSMIUM_INDEX_MAP_SPARSE_FILE_ARRAY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <string>
+#include <vector>
+
+#include <osmium/index/detail/mmap_vector_file.hpp>
+#include <osmium/index/detail/vector_map.hpp>
+#include <osmium/index/detail/create_map_with_fd.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_SPARSE_FILE_ARRAY
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            template <typename TId, typename TValue>
+            using SparseFileArray = VectorBasedSparseMap<TId, TValue, osmium::detail::mmap_vector_file>;
+
+            template <typename TId, typename TValue>
+            struct create_map<TId, TValue, SparseFileArray> {
+                SparseFileArray<TId, TValue>* operator()(const std::vector<std::string>& config) {
+                    return osmium::index::detail::create_map_with_fd<SparseFileArray<TId, TValue>>(config);
+                }
+            };
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_SPARSE_FILE_ARRAY_HPP
diff --git a/contrib/libosmium/osmium/index/map/sparse_mem_array.hpp b/contrib/libosmium/osmium/index/map/sparse_mem_array.hpp
new file mode 100644
index 0000000..9adf41f
--- /dev/null
+++ b/contrib/libosmium/osmium/index/map/sparse_mem_array.hpp
@@ -0,0 +1,60 @@
+#ifndef OSMIUM_INDEX_MAP_SPARSE_MEM_ARRAY_HPP
+#define OSMIUM_INDEX_MAP_SPARSE_MEM_ARRAY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <vector>
+
+#include <osmium/index/detail/vector_map.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_SPARSE_MEM_ARRAY
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            template <typename T>
+            using StdVectorWrap = std::vector<T>;
+
+            template <typename TId, typename TValue>
+            using SparseMemArray = VectorBasedSparseMap<TId, TValue, StdVectorWrap>;
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_SPARSE_MEM_ARRAY_HPP
diff --git a/contrib/libosmium/osmium/index/map/sparse_mem_map.hpp b/contrib/libosmium/osmium/index/map/sparse_mem_map.hpp
new file mode 100644
index 0000000..9bad07e
--- /dev/null
+++ b/contrib/libosmium/osmium/index/map/sparse_mem_map.hpp
@@ -0,0 +1,116 @@
+#ifndef OSMIUM_INDEX_MAP_SPARSE_MEM_MAP_HPP
+#define OSMIUM_INDEX_MAP_SPARSE_MEM_MAP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm> // IWYU pragma: keep (for std::copy)
+#include <cstddef>
+#include <iterator>
+#include <map>
+#include <stdexcept>
+#include <vector>
+
+#include <osmium/index/map.hpp>
+#include <osmium/index/index.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_SPARSE_MEM_MAP
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            /**
+             * This implementation uses std::map internally. It uses rather a
+             * lot of memory, but might make sense for small maps.
+             */
+            template <typename TId, typename TValue>
+            class SparseMemMap : public osmium::index::map::Map<TId, TValue> {
+
+                // This is a rough estimate for the memory needed for each
+                // element in the map (id + value + pointers to left, right,
+                // and parent plus some overhead for color of red-black-tree
+                // or similar).
+                static constexpr size_t element_size = sizeof(TId) + sizeof(TValue) + sizeof(void*) * 4;
+
+                std::map<TId, TValue> m_elements;
+
+            public:
+
+                SparseMemMap() = default;
+
+                ~SparseMemMap() noexcept override final = default;
+
+                void set(const TId id, const TValue value) override final {
+                    m_elements[id] = value;
+                }
+
+                const TValue get(const TId id) const override final {
+                    auto it = m_elements.find(id);
+                    if (it == m_elements.end()) {
+                        not_found_error(id);
+                    }
+                    return it->second;
+                }
+
+                size_t size() const noexcept override final {
+                    return m_elements.size();
+                }
+
+                size_t used_memory() const noexcept override final {
+                    return element_size * m_elements.size();
+                }
+
+                void clear() override final {
+                    m_elements.clear();
+                }
+
+                void dump_as_list(const int fd) override final {
+                    typedef typename std::map<TId, TValue>::value_type t;
+                    std::vector<t> v;
+                    v.reserve(m_elements.size());
+                    std::copy(m_elements.cbegin(), m_elements.cend(), std::back_inserter(v));
+                    osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(t) * v.size());
+                }
+
+            }; // class SparseMemMap
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_SPARSE_MEM_MAP_HPP
diff --git a/contrib/libosmium/osmium/index/map/sparse_mem_table.hpp b/contrib/libosmium/osmium/index/map/sparse_mem_table.hpp
new file mode 100644
index 0000000..032400e
--- /dev/null
+++ b/contrib/libosmium/osmium/index/map/sparse_mem_table.hpp
@@ -0,0 +1,147 @@
+#ifndef OSMIUM_INDEX_MAP_SPARSE_MEM_TABLE_HPP
+#define OSMIUM_INDEX_MAP_SPARSE_MEM_TABLE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#ifdef OSMIUM_WITH_SPARSEHASH
+
+#include <cstddef>
+#include <utility>
+#include <vector>
+
+#include <google/sparsetable>
+
+#include <osmium/index/index.hpp>
+#include <osmium/index/map.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_SPARSE_MEM_TABLE
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            /**
+            * The SparseMemTable index stores elements in a Google sparsetable,
+            * a data structure that can hold sparsly filled tables in a
+            * space efficient way. It will resize automatically.
+            *
+            * Use this index if the ID space is only sparsly
+            * populated, such as when working with smaller OSM files (like
+            * country extracts).
+            *
+            * This will only work on 64 bit machines.
+            */
+            template <typename TId, typename TValue>
+            class SparseMemTable : public osmium::index::map::Map<TId, TValue> {
+
+                TId m_grow_size;
+
+                google::sparsetable<TValue> m_elements;
+
+                static_assert(sizeof(typename google::sparsetable<TValue>::size_type) >= 8, "google::sparsetable needs 64bit machine");
+
+            public:
+
+                /**
+                * Constructor.
+                *
+                * @param grow_size The initial size of the index (ie number of
+                *                  elements that fit into the index).
+                *                  The storage will grow by at least this size
+                *                  every time it runs out of space.
+                */
+                explicit SparseMemTable(const TId grow_size = 10000) :
+                    m_grow_size(grow_size),
+                    m_elements(grow_size) {
+                }
+
+                ~SparseMemTable() noexcept override final = default;
+
+                void set(const TId id, const TValue value) override final {
+                    if (id >= m_elements.size()) {
+                        m_elements.resize(id + m_grow_size);
+                    }
+                    m_elements[id] = value;
+                }
+
+                const TValue get(const TId id) const override final {
+                    if (id >= m_elements.size()) {
+                        not_found_error(id);
+                    }
+                    if (m_elements[id] == osmium::index::empty_value<TValue>()) {
+                        not_found_error(id);
+                    }
+                    return m_elements[id];
+                }
+
+                size_t size() const override final {
+                    return m_elements.size();
+                }
+
+                size_t used_memory() const override final {
+                    // unused elements use 1 bit, used elements sizeof(TValue) bytes
+                    // http://google-sparsehash.googlecode.com/svn/trunk/doc/sparsetable.html
+                    return (m_elements.size() / 8) + (m_elements.num_nonempty() * sizeof(TValue));
+                }
+
+                void clear() override final {
+                    m_elements.clear();
+                }
+
+                void dump_as_list(const int fd) override final {
+                    std::vector<std::pair<TId, TValue>> v;
+                    v.reserve(m_elements.size());
+                    int n = 0;
+                    for (const TValue value : m_elements) {
+                        if (value != osmium::index::empty_value<TValue>()) {
+                            v.emplace_back(n, value);
+                        }
+                        ++n;
+                    }
+                    osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(std::pair<TId, TValue>) * v.size());
+                }
+
+            }; // class SparseMemTable
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_WITH_SPARSEHASH
+
+#endif // OSMIUM_INDEX_BYID_SPARSE_MEM_TABLE_HPP
diff --git a/contrib/libosmium/osmium/index/map/sparse_mmap_array.hpp b/contrib/libosmium/osmium/index/map/sparse_mmap_array.hpp
new file mode 100644
index 0000000..c85e2c9
--- /dev/null
+++ b/contrib/libosmium/osmium/index/map/sparse_mmap_array.hpp
@@ -0,0 +1,60 @@
+#ifndef OSMIUM_INDEX_MAP_SPARSE_MMAP_ARRAY_HPP
+#define OSMIUM_INDEX_MAP_SPARSE_MMAP_ARRAY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#ifdef __linux__
+
+#include <osmium/index/detail/mmap_vector_anon.hpp>
+#include <osmium/index/detail/vector_map.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_SPARSE_MMAP_ARRAY
+
+namespace osmium {
+
+    namespace index {
+
+        namespace map {
+
+            template <typename TId, typename TValue>
+            using SparseMmapArray = VectorBasedSparseMap<TId, TValue, osmium::detail::mmap_vector_anon>;
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // __linux__
+
+#endif // OSMIUM_INDEX_MAP_SPARSE_MMAP_ARRAY_HPP
diff --git a/contrib/libosmium/osmium/index/multimap.hpp b/contrib/libosmium/osmium/index/multimap.hpp
new file mode 100644
index 0000000..c817b6f
--- /dev/null
+++ b/contrib/libosmium/osmium/index/multimap.hpp
@@ -0,0 +1,127 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_HPP
+#define OSMIUM_INDEX_MULTIMAP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <stdexcept>
+#include <type_traits>
+#include <utility>
+
+namespace osmium {
+
+    namespace index {
+
+        /**
+         * @brief Key-value containers with multiple values for an integer key
+         */
+        namespace multimap {
+
+            template <typename TId, typename TValue>
+            class Multimap {
+
+                static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, "TId template parameter for class Multimap must be unsigned integral type");
+
+                typedef typename std::pair<TId, TValue> element_type;
+
+                Multimap(const Multimap&) = delete;
+                Multimap& operator=(const Multimap&) = delete;
+
+            protected:
+
+                Multimap(Multimap&&) = default;
+                Multimap& operator=(Multimap&&) = default;
+
+            public:
+
+                /// The "key" type, usually osmium::unsigned_object_id_type.
+                typedef TId key_type;
+
+                /// The "value" type, usually a Location or size_t.
+                typedef TValue value_type;
+
+                Multimap() = default;
+
+                virtual ~Multimap() noexcept = default;
+
+                /// Set the field with id to value.
+                virtual void set(const TId id, const TValue value) = 0;
+
+                typedef element_type* iterator;
+
+//                virtual std::pair<iterator, iterator> get_all(const TId id) const = 0;
+
+                /**
+                 * Get the approximate number of items in the storage. The storage
+                 * might allocate memory in blocks, so this size might not be
+                 * accurate. You can not use this to find out how much memory the
+                 * storage uses. Use used_memory() for that.
+                 */
+                virtual size_t size() const = 0;
+
+                /**
+                 * Get the memory used for this storage in bytes. Note that this
+                 * is not necessarily entirely accurate but an approximation.
+                 * For storage classes that store the data in memory, this is
+                 * the main memory used, for storage classes storing data on disk
+                 * this is the memory used on disk.
+                 */
+                virtual size_t used_memory() const = 0;
+
+                /**
+                 * Clear memory used for this storage. After this you can not
+                 * use the storage container any more.
+                 */
+                virtual void clear() = 0;
+
+                /**
+                 * Sort data in map. Call this after writing all data and
+                 * before reading. Not all implementations need this.
+                 */
+                virtual void sort() {
+                    // default implementation is empty
+                }
+
+                virtual void dump_as_list(const int /*fd*/) {
+                    std::runtime_error("can't dump as list");
+                }
+
+            }; // class Multimap
+
+        } // namespace map
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_HPP
diff --git a/contrib/libosmium/osmium/index/multimap/all.hpp b/contrib/libosmium/osmium/index/multimap/all.hpp
new file mode 100644
index 0000000..8b0ae99
--- /dev/null
+++ b/contrib/libosmium/osmium/index/multimap/all.hpp
@@ -0,0 +1,41 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_ALL_HPP
+#define OSMIUM_INDEX_MULTIMAP_ALL_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/index/multimap/sparse_file_array.hpp>   // IWYU pragma: keep
+#include <osmium/index/multimap/sparse_mem_array.hpp>    // IWYU pragma: keep
+#include <osmium/index/multimap/sparse_mem_multimap.hpp> // IWYU pragma: keep
+#include <osmium/index/multimap/sparse_mmap_array.hpp>   // IWYU pragma: keep
+
+#endif // OSMIUM_INDEX_MULTIMAP_ALL_HPP
diff --git a/contrib/libosmium/osmium/index/multimap/hybrid.hpp b/contrib/libosmium/osmium/index/multimap/hybrid.hpp
new file mode 100644
index 0000000..cdf14a3
--- /dev/null
+++ b/contrib/libosmium/osmium/index/multimap/hybrid.hpp
@@ -0,0 +1,204 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_HYBRID_HPP
+#define OSMIUM_INDEX_MULTIMAP_HYBRID_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <utility>
+
+#include <osmium/index/index.hpp>
+#include <osmium/index/multimap.hpp>
+#include <osmium/index/multimap/sparse_mem_array.hpp>
+#include <osmium/index/multimap/sparse_mem_multimap.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace multimap {
+
+            template <typename TId, typename TValue>
+            class HybridIterator {
+
+                typedef SparseMemArray<TId, TValue> main_map_type;
+                typedef SparseMemMultimap<TId, TValue> extra_map_type;
+
+                typedef typename std::pair<TId, TValue> element_type;
+
+                typename main_map_type::iterator m_begin_main;
+                typename main_map_type::iterator m_end_main;
+                typename extra_map_type::iterator m_begin_extra;
+                typename extra_map_type::iterator m_end_extra;
+
+            public:
+
+                 HybridIterator(typename main_map_type::iterator begin_main,
+                                typename main_map_type::iterator end_main,
+                                typename extra_map_type::iterator begin_extra,
+                                typename extra_map_type::iterator end_extra) :
+                    m_begin_main(begin_main),
+                    m_end_main(end_main),
+                    m_begin_extra(begin_extra),
+                    m_end_extra(end_extra) {
+                }
+
+                ~HybridIterator() noexcept = default;
+
+                HybridIterator& operator++() {
+                    if (m_begin_main == m_end_main) {
+                        ++m_begin_extra;
+                    } else {
+                        ++m_begin_main;
+                        while (m_begin_main != m_end_main && m_begin_main->second == osmium::index::empty_value<TValue>()) { // ignore removed elements
+                            ++m_begin_main;
+                        }
+                    }
+                    return *this;
+                }
+
+                HybridIterator<TId, TValue> operator++(int) {
+                    auto tmp(*this);
+                    operator++();
+                    return tmp;
+                }
+
+                bool operator==(const HybridIterator& rhs) const {
+                    return m_begin_main == rhs.m_begin_main &&
+                           m_end_main   == rhs.m_end_main &&
+                           m_begin_extra == rhs.m_begin_extra &&
+                           m_end_extra   == rhs.m_end_extra;
+                }
+
+                bool operator!=(const HybridIterator& rhs) const {
+                    return ! operator==(rhs);
+                }
+
+                const element_type& operator*() {
+                    if (m_begin_main == m_end_main) {
+                        return *m_begin_extra;
+                    } else {
+                        return *m_begin_main;
+                    }
+                }
+
+                const element_type* operator->() {
+                    return &operator*();
+                }
+
+            }; // class HybridIterator
+
+            template <typename TId, typename TValue>
+            class Hybrid : public Multimap<TId, TValue> {
+
+                typedef SparseMemArray<TId, TValue> main_map_type;
+                typedef SparseMemMultimap<TId, TValue> extra_map_type;
+
+                main_map_type m_main;
+                extra_map_type m_extra;
+
+            public:
+
+                typedef HybridIterator<TId, TValue> iterator;
+                typedef const HybridIterator<TId, TValue> const_iterator;
+
+                Hybrid() :
+                    m_main(),
+                    m_extra() {
+                }
+
+                ~Hybrid() noexcept = default;
+
+                size_t size() const override final {
+                    return m_main.size() + m_extra.size();
+                }
+
+                size_t used_memory() const override final {
+                    return m_main.used_memory() + m_extra.used_memory();
+                }
+
+                void reserve(const size_t size) {
+                    m_main.reserve(size);
+                }
+
+                void unsorted_set(const TId id, const TValue value) {
+                    m_main.set(id, value);
+                }
+
+                void set(const TId id, const TValue value) override final {
+                    m_extra.set(id, value);
+                }
+
+                std::pair<iterator, iterator> get_all(const TId id) {
+                    auto result_main = m_main.get_all(id);
+                    auto result_extra = m_extra.get_all(id);
+                    return std::make_pair(iterator(result_main.first, result_main.second, result_extra.first, result_extra.second),
+                                          iterator(result_main.second, result_main.second, result_extra.second, result_extra.second));
+                }
+
+                void remove(const TId id, const TValue value) {
+                    m_main.remove(id, value);
+                    m_extra.remove(id, value);
+                }
+
+                void consolidate() {
+                    m_main.erase_removed();
+                    for (const auto& element : m_extra) {
+                        m_main.set(element.first, element.second);
+                    }
+                    m_extra.clear();
+                    m_main.sort();
+                }
+
+                void dump_as_list(const int fd) override final {
+                    consolidate();
+                    m_main.dump_as_list(fd);
+                }
+
+                void clear() override final {
+                    m_main.clear();
+                    m_extra.clear();
+                }
+
+                void sort() override final {
+                    m_main.sort();
+                }
+
+            }; // class Hybrid
+
+        } // namespace multimap
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_HYBRID_HPP
diff --git a/contrib/libosmium/osmium/index/multimap/sparse_file_array.hpp b/contrib/libosmium/osmium/index/multimap/sparse_file_array.hpp
new file mode 100644
index 0000000..0b9ae92
--- /dev/null
+++ b/contrib/libosmium/osmium/index/multimap/sparse_file_array.hpp
@@ -0,0 +1,54 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_SPARSE_FILE_ARRAY_HPP
+#define OSMIUM_INDEX_MULTIMAP_SPARSE_FILE_ARRAY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/index/detail/mmap_vector_file.hpp>
+#include <osmium/index/detail/vector_multimap.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace multimap {
+
+            template <typename TId, typename TValue>
+            using SparseFileArray = VectorBasedSparseMultimap<TId, TValue, osmium::detail::mmap_vector_file>;
+
+        } // namespace multimap
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_SPARSE_FILE_ARRAY_HPP
diff --git a/contrib/libosmium/osmium/index/multimap/sparse_mem_array.hpp b/contrib/libosmium/osmium/index/multimap/sparse_mem_array.hpp
new file mode 100644
index 0000000..c4140cb
--- /dev/null
+++ b/contrib/libosmium/osmium/index/multimap/sparse_mem_array.hpp
@@ -0,0 +1,58 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_SPARSE_MEM_ARRAY_HPP
+#define OSMIUM_INDEX_MULTIMAP_SPARSE_MEM_ARRAY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <vector>
+
+#include <osmium/index/detail/vector_multimap.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace multimap {
+
+            template <typename T>
+            using StdVectorWrap = std::vector<T>;
+
+            template <typename TId, typename TValue>
+            using SparseMemArray = VectorBasedSparseMultimap<TId, TValue, StdVectorWrap>;
+
+        } // namespace multimap
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_SPARSE_MEM_ARRAY_HPP
diff --git a/contrib/libosmium/osmium/index/multimap/sparse_mem_multimap.hpp b/contrib/libosmium/osmium/index/multimap/sparse_mem_multimap.hpp
new file mode 100644
index 0000000..353e357
--- /dev/null
+++ b/contrib/libosmium/osmium/index/multimap/sparse_mem_multimap.hpp
@@ -0,0 +1,151 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_SPARSE_MEM_MULTIMAP_HPP
+#define OSMIUM_INDEX_MULTIMAP_SPARSE_MEM_MULTIMAP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <map>
+#include <utility>
+#include <vector>
+
+#include <osmium/index/multimap.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace multimap {
+
+            /**
+             * This implementation uses std::multimap internally. It uses rather a
+             * lot of memory, but might make sense for small maps.
+             */
+            template <typename TId, typename TValue>
+            class SparseMemMultimap : public osmium::index::multimap::Multimap<TId, TValue> {
+
+                // This is a rough estimate for the memory needed for each
+                // element in the map (id + value + pointers to left, right,
+                // and parent plus some overhead for color of red-black-tree
+                // or similar).
+                static constexpr size_t element_size = sizeof(TId) + sizeof(TValue) + sizeof(void*) * 4;
+
+            public:
+
+                typedef typename std::multimap<const TId, TValue> collection_type;
+                typedef typename collection_type::iterator iterator;
+                typedef typename collection_type::const_iterator const_iterator;
+                typedef typename collection_type::value_type value_type;
+
+                typedef typename std::pair<TId, TValue> element_type;
+
+            private:
+
+                collection_type m_elements;
+
+            public:
+
+                SparseMemMultimap() = default;
+
+                ~SparseMemMultimap() noexcept override final = default;
+
+                void unsorted_set(const TId id, const TValue value) {
+                    m_elements.emplace(id, value);
+                }
+
+                void set(const TId id, const TValue value) override final {
+                    m_elements.emplace(id, value);
+                }
+
+                std::pair<iterator, iterator> get_all(const TId id) {
+                    return m_elements.equal_range(id);
+                }
+
+                std::pair<const_iterator, const_iterator> get_all(const TId id) const {
+                    return m_elements.equal_range(id);
+                }
+
+                void remove(const TId id, const TValue value) {
+                    std::pair<iterator, iterator> r = get_all(id);
+                    for (iterator it = r.first; it != r.second; ++it) {
+                        if (it->second == value) {
+                            m_elements.erase(it);
+                            return;
+                        }
+                    }
+                }
+
+                iterator begin() {
+                    return m_elements.begin();
+                }
+
+                iterator end() {
+                    return m_elements.end();
+                }
+
+                size_t size() const override final {
+                    return m_elements.size();
+                }
+
+                size_t used_memory() const override final {
+                    return element_size * m_elements.size();
+                }
+
+                void clear() override final {
+                    m_elements.clear();
+                }
+
+                void consolidate() {
+                    // intentionally left blank
+                }
+
+                void dump_as_list(const int fd) override final {
+                    std::vector<element_type> v;
+                    v.reserve(m_elements.size());
+                    for (const auto& element : m_elements) {
+                        v.emplace_back(element.first, element.second);
+                    }
+                    std::sort(v.begin(), v.end());
+                    osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(element_type) * v.size());
+                }
+
+            }; // class SparseMemMultimap
+
+        } // namespace multimap
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_SPARSE_MEM_MULTIMAP_HPP
diff --git a/contrib/libosmium/osmium/index/multimap/sparse_mmap_array.hpp b/contrib/libosmium/osmium/index/multimap/sparse_mmap_array.hpp
new file mode 100644
index 0000000..9f92555
--- /dev/null
+++ b/contrib/libosmium/osmium/index/multimap/sparse_mmap_array.hpp
@@ -0,0 +1,58 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_SPARSE_MMAP_ARRAY_HPP
+#define OSMIUM_INDEX_MULTIMAP_SPARSE_MMAP_ARRAY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#ifdef __linux__
+
+#include <osmium/index/detail/mmap_vector_anon.hpp>
+#include <osmium/index/detail/vector_multimap.hpp>
+
+namespace osmium {
+
+    namespace index {
+
+        namespace multimap {
+
+            template <typename TId, typename TValue>
+            using SparseMmapArray = VectorBasedSparseMultimap<TId, TValue, osmium::detail::mmap_vector_anon>;
+
+        } // namespace multimap
+
+    } // namespace index
+
+} // namespace osmium
+
+#endif // __linux__
+
+#endif // OSMIUM_INDEX_MULTIMAP_SPARSE_MMAP_ARRAY_HPP
diff --git a/contrib/libosmium/osmium/index/node_locations_map.hpp b/contrib/libosmium/osmium/index/node_locations_map.hpp
new file mode 100644
index 0000000..ca4b136
--- /dev/null
+++ b/contrib/libosmium/osmium/index/node_locations_map.hpp
@@ -0,0 +1,70 @@
+#ifndef OSMIUM_INDEX_NODE_LOCATIONS_MAP_HPP
+#define OSMIUM_INDEX_NODE_LOCATIONS_MAP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/index/map.hpp> // IWYU pragma: keep
+
+#ifdef OSMIUM_HAS_INDEX_MAP_DENSE_FILE_ARRAY
+    REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::DenseFileArray, dense_file_array)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_DENSE_MEM_ARRAY
+    REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::DenseMemArray, dense_mem_array)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_DENSE_MMAP_ARRAY
+    REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::DenseMmapArray, dense_mmap_array)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_SPARSE_FILE_ARRAY
+    REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseFileArray, sparse_file_array)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_SPARSE_MEM_ARRAY
+    REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMemArray, sparse_mem_array)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_SPARSE_MEM_MAP
+    REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMemMap, sparse_mem_map)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_SPARSE_MEM_TABLE
+    REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMemTable, sparse_mem_table)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_SPARSE_MMAP_ARRAY
+    REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMmapArray, sparse_mmap_array)
+#endif
+
+#endif // OSMIUM_INDEX_NODE_LOCATIONS_MAP_HPP
diff --git a/contrib/libosmium/osmium/io/any_compression.hpp b/contrib/libosmium/osmium/io/any_compression.hpp
new file mode 100644
index 0000000..00e8ee2
--- /dev/null
+++ b/contrib/libosmium/osmium/io/any_compression.hpp
@@ -0,0 +1,48 @@
+#ifndef OSMIUM_IO_ANY_COMPRESSION_HPP
+#define OSMIUM_IO_ANY_COMPRESSION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * Include this file if you want to read or write compressed OSM XML files.
+ *
+ * @attention If you include this file, you'll need to link with `libz`
+ *            and `libbz2`.
+ */
+
+#include <osmium/io/bzip2_compression.hpp> // IWYU pragma: export
+#include <osmium/io/gzip_compression.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_ANY_COMPRESSION_HPP
diff --git a/contrib/libosmium/osmium/io/any_input.hpp b/contrib/libosmium/osmium/io/any_input.hpp
new file mode 100644
index 0000000..36f43b7
--- /dev/null
+++ b/contrib/libosmium/osmium/io/any_input.hpp
@@ -0,0 +1,52 @@
+#ifndef OSMIUM_IO_ANY_INPUT_HPP
+#define OSMIUM_IO_ANY_INPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * Include this file if you want to read all kinds of OSM files.
+ *
+ * @attention If you include this file, you'll need to link with
+ *            `ws2_32` (Windows only), `libexpat`, `libz`, `libbz2`,
+ *            and enable multithreading.
+ */
+
+#include <osmium/io/any_compression.hpp> // IWYU pragma: export
+
+#include <osmium/io/pbf_input.hpp> // IWYU pragma: export
+#include <osmium/io/xml_input.hpp> // IWYU pragma: export
+#include <osmium/io/o5m_input.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_ANY_INPUT_HPP
diff --git a/contrib/libosmium/osmium/io/any_output.hpp b/contrib/libosmium/osmium/io/any_output.hpp
new file mode 100644
index 0000000..990a27b
--- /dev/null
+++ b/contrib/libosmium/osmium/io/any_output.hpp
@@ -0,0 +1,53 @@
+#ifndef OSMIUM_IO_ANY_OUTPUT_HPP
+#define OSMIUM_IO_ANY_OUTPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * Include this file if you want to write all kinds of OSM files.
+ *
+ * @attention If you include this file, you'll need to link with
+ *            `ws2_32` (Windows only), `libz`, `libbz2`, and enable
+ *            multithreading.
+ */
+
+#include <osmium/io/any_compression.hpp> // IWYU pragma: export
+
+#include <osmium/io/debug_output.hpp> // IWYU pragma: export
+#include <osmium/io/opl_output.hpp> // IWYU pragma: export
+#include <osmium/io/pbf_output.hpp> // IWYU pragma: export
+#include <osmium/io/xml_output.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_ANY_OUTPUT_HPP
diff --git a/contrib/libosmium/osmium/io/bzip2_compression.hpp b/contrib/libosmium/osmium/io/bzip2_compression.hpp
new file mode 100644
index 0000000..ad4b877
--- /dev/null
+++ b/contrib/libosmium/osmium/io/bzip2_compression.hpp
@@ -0,0 +1,321 @@
+#ifndef OSMIUM_IO_BZIP2_COMPRESSION_HPP
+#define OSMIUM_IO_BZIP2_COMPRESSION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * Include this file if you want to read or write bzip2-compressed OSM XML
+ * files.
+ *
+ * @attention If you include this file, you'll need to link with `libbz2`.
+ */
+
+#include <cerrno>
+#include <cstddef>
+#include <cstdio>
+#include <stdexcept>
+#include <string>
+
+#include <bzlib.h>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/error.hpp>
+#include <osmium/io/file_compression.hpp>
+#include <osmium/io/writer_options.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when there are problems compressing or
+     * decompressing bzip2 files.
+     */
+    struct bzip2_error : public io_error {
+
+        int bzip2_error_code;
+        int system_errno;
+
+        bzip2_error(const std::string& what, int error_code) :
+            io_error(what),
+            bzip2_error_code(error_code),
+            system_errno(error_code == BZ_IO_ERROR ? errno : 0) {
+        }
+
+    }; // struct bzip2_error
+
+    namespace io {
+
+        namespace detail {
+
+            OSMIUM_NORETURN inline void throw_bzip2_error(BZFILE* bzfile, const char* msg, int bzlib_error = 0) {
+                std::string error("bzip2 error: ");
+                error += msg;
+                error += ": ";
+                int errnum = bzlib_error;
+                if (bzlib_error) {
+                    error += std::to_string(bzlib_error);
+                } else {
+                    error += ::BZ2_bzerror(bzfile, &errnum);
+                }
+                throw osmium::bzip2_error(error, errnum);
+            }
+
+        } // namespace detail
+
+        class Bzip2Compressor : public Compressor {
+
+            FILE* m_file;
+            int m_bzerror;
+            BZFILE* m_bzfile;
+
+        public:
+
+            explicit Bzip2Compressor(int fd, fsync sync) :
+                Compressor(sync),
+                m_file(fdopen(dup(fd), "wb")),
+                m_bzerror(BZ_OK),
+                m_bzfile(::BZ2_bzWriteOpen(&m_bzerror, m_file, 6, 0, 0)) {
+                if (!m_bzfile) {
+                    detail::throw_bzip2_error(m_bzfile, "write open failed", m_bzerror);
+                }
+            }
+
+            ~Bzip2Compressor() noexcept override final {
+                try {
+                    close();
+                } catch (...) {
+                    // Ignore any exceptions because destructor must not throw.
+                }
+            }
+
+            void write(const std::string& data) override final {
+                int error;
+                ::BZ2_bzWrite(&error, m_bzfile, const_cast<char*>(data.data()), static_cast_with_assert<int>(data.size()));
+                if (error != BZ_OK && error != BZ_STREAM_END) {
+                    detail::throw_bzip2_error(m_bzfile, "write failed", error);
+                }
+            }
+
+            void close() override final {
+                if (m_bzfile) {
+                    int error;
+                    ::BZ2_bzWriteClose(&error, m_bzfile, 0, nullptr, nullptr);
+                    m_bzfile = nullptr;
+                    if (m_file) {
+                        if (do_fsync()) {
+                            osmium::io::detail::reliable_fsync(::fileno(m_file));
+                        }
+                        if (fclose(m_file) != 0) {
+                            throw std::system_error(errno, std::system_category(), "Close failed");
+                        }
+                    }
+                    if (error != BZ_OK) {
+                        detail::throw_bzip2_error(m_bzfile, "write close failed", error);
+                    }
+                }
+            }
+
+        }; // class Bzip2Compressor
+
+        class Bzip2Decompressor : public Decompressor {
+
+            FILE* m_file;
+            int m_bzerror;
+            BZFILE* m_bzfile;
+            bool m_stream_end {false};
+
+        public:
+
+            Bzip2Decompressor(int fd) :
+                Decompressor(),
+                m_file(fdopen(dup(fd), "rb")),
+                m_bzerror(BZ_OK),
+                m_bzfile(::BZ2_bzReadOpen(&m_bzerror, m_file, 0, 0, nullptr, 0)) {
+                if (!m_bzfile) {
+                    detail::throw_bzip2_error(m_bzfile, "read open failed", m_bzerror);
+                }
+            }
+
+            ~Bzip2Decompressor() noexcept override final {
+                try {
+                    close();
+                } catch (...) {
+                    // Ignore any exceptions because destructor must not throw.
+                }
+            }
+
+            std::string read() override final {
+                std::string buffer;
+
+                if (!m_stream_end) {
+                    buffer.resize(osmium::io::Decompressor::input_buffer_size);
+                    int error;
+                    int nread = ::BZ2_bzRead(&error, m_bzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<int>(buffer.size()));
+                    if (error != BZ_OK && error != BZ_STREAM_END) {
+                        detail::throw_bzip2_error(m_bzfile, "read failed", error);
+                    }
+                    if (error == BZ_STREAM_END) {
+                        void* unused;
+                        int nunused;
+                        if (! feof(m_file)) {
+                            ::BZ2_bzReadGetUnused(&error, m_bzfile, &unused, &nunused);
+                            if (error != BZ_OK) {
+                                detail::throw_bzip2_error(m_bzfile, "get unused failed", error);
+                            }
+                            std::string unused_data(static_cast<const char*>(unused), static_cast<std::string::size_type>(nunused));
+                            ::BZ2_bzReadClose(&error, m_bzfile);
+                            if (error != BZ_OK) {
+                                detail::throw_bzip2_error(m_bzfile, "read close failed", error);
+                            }
+                            m_bzfile = ::BZ2_bzReadOpen(&error, m_file, 0, 0, const_cast<void*>(static_cast<const void*>(unused_data.data())), static_cast_with_assert<int>(unused_data.size()));
+                            if (error != BZ_OK) {
+                                detail::throw_bzip2_error(m_bzfile, "read open failed", error);
+                            }
+                        } else {
+                            m_stream_end = true;
+                        }
+                    }
+                    buffer.resize(static_cast<std::string::size_type>(nread));
+                }
+
+                return buffer;
+            }
+
+            void close() override final {
+                if (m_bzfile) {
+                    int error;
+                    ::BZ2_bzReadClose(&error, m_bzfile);
+                    m_bzfile = nullptr;
+                    if (m_file) {
+                        if (fclose(m_file) != 0) {
+                            throw std::system_error(errno, std::system_category(), "Close failed");
+                        }
+                    }
+                    if (error != BZ_OK) {
+                        detail::throw_bzip2_error(m_bzfile, "read close failed", error);
+                    }
+                }
+            }
+
+        }; // class Bzip2Decompressor
+
+        class Bzip2BufferDecompressor : public Decompressor {
+
+            const char* m_buffer;
+            size_t m_buffer_size;
+            bz_stream m_bzstream;
+
+        public:
+
+            Bzip2BufferDecompressor(const char* buffer, size_t size) :
+                m_buffer(buffer),
+                m_buffer_size(size),
+                m_bzstream() {
+                m_bzstream.next_in = const_cast<char*>(buffer);
+                m_bzstream.avail_in = static_cast_with_assert<unsigned int>(size);
+                int result = BZ2_bzDecompressInit(&m_bzstream, 0, 0);
+                if (result != BZ_OK) {
+                    std::string message("bzip2 error: decompression init failed: ");
+                    throw bzip2_error(message, result);
+                }
+            }
+
+            ~Bzip2BufferDecompressor() noexcept override final {
+                try {
+                    close();
+                } catch (...) {
+                    // Ignore any exceptions because destructor must not throw.
+                }
+            }
+
+            std::string read() override final {
+                std::string output;
+
+                if (m_buffer) {
+                    const size_t buffer_size = 10240;
+                    output.resize(buffer_size);
+                    m_bzstream.next_out = const_cast<char*>(output.data());
+                    m_bzstream.avail_out = buffer_size;
+                    int result = BZ2_bzDecompress(&m_bzstream);
+
+                    if (result != BZ_OK) {
+                        m_buffer = nullptr;
+                        m_buffer_size = 0;
+                    }
+
+                    if (result != BZ_OK && result != BZ_STREAM_END) {
+                        std::string message("bzip2 error: decompress failed: ");
+                        throw bzip2_error(message, result);
+                    }
+
+                    output.resize(static_cast<unsigned long>(m_bzstream.next_out - output.data()));
+                }
+
+                return output;
+            }
+
+            void close() override final {
+                BZ2_bzDecompressEnd(&m_bzstream);
+            }
+
+        }; // class Bzip2BufferDecompressor
+
+        namespace detail {
+
+            // we want the register_compression() function to run, setting
+            // the variable is only a side-effect, it will never be used
+            const bool registered_bzip2_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::bzip2,
+                [](int fd, fsync sync) { return new osmium::io::Bzip2Compressor(fd, sync); },
+                [](int fd) { return new osmium::io::Bzip2Decompressor(fd); },
+                [](const char* buffer, size_t size) { return new osmium::io::Bzip2BufferDecompressor(buffer, size); }
+            );
+
+            // dummy function to silence the unused variable warning from above
+            inline bool get_registered_bzip2_compression() noexcept {
+                return registered_bzip2_compression;
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_BZIP2_COMPRESSION_HPP
diff --git a/contrib/libosmium/osmium/io/compression.hpp b/contrib/libosmium/osmium/io/compression.hpp
new file mode 100644
index 0000000..4a69be7
--- /dev/null
+++ b/contrib/libosmium/osmium/io/compression.hpp
@@ -0,0 +1,321 @@
+#ifndef OSMIUM_IO_COMPRESSION_HPP
+#define OSMIUM_IO_COMPRESSION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cerrno>
+#include <functional>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <system_error>
+#include <tuple>
+#include <utility>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
+
+#include <osmium/io/detail/read_write.hpp>
+#include <osmium/io/error.hpp>
+#include <osmium/io/file_compression.hpp>
+#include <osmium/io/writer_options.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        class Compressor {
+
+            fsync m_fsync;
+
+        protected:
+
+            bool do_fsync() const {
+                return m_fsync == fsync::yes;
+            }
+
+        public:
+
+            explicit Compressor(fsync sync) :
+                m_fsync(sync) {
+            }
+
+            virtual ~Compressor() noexcept {
+            }
+
+            virtual void write(const std::string& data) = 0;
+
+            virtual void close() = 0;
+
+        }; // class Compressor
+
+        class Decompressor {
+
+        public:
+
+            static constexpr unsigned int input_buffer_size = 1024 * 1024;
+
+            Decompressor() = default;
+
+            Decompressor(const Decompressor&) = delete;
+            Decompressor& operator=(const Decompressor&) = delete;
+
+            Decompressor(Decompressor&&) = delete;
+            Decompressor& operator=(Decompressor&&) = delete;
+
+            virtual ~Decompressor() noexcept {
+            }
+
+            virtual std::string read() = 0;
+
+            virtual void close() = 0;
+
+        }; // class Decompressor
+
+        /**
+         * This singleton factory class is used to register compression
+         * algorithms used for reading and writing OSM files.
+         *
+         * For each algorithm we store two functions that construct
+         * a compressor and decompressor object, respectively.
+         */
+        class CompressionFactory {
+
+        public:
+
+            typedef std::function<osmium::io::Compressor*(int, fsync)> create_compressor_type;
+            typedef std::function<osmium::io::Decompressor*(int)> create_decompressor_type_fd;
+            typedef std::function<osmium::io::Decompressor*(const char*, size_t)> create_decompressor_type_buffer;
+
+        private:
+
+            typedef std::map<const osmium::io::file_compression,
+                             std::tuple<create_compressor_type,
+                                        create_decompressor_type_fd,
+                                        create_decompressor_type_buffer>> compression_map_type;
+
+            compression_map_type m_callbacks;
+
+            CompressionFactory() = default;
+
+            CompressionFactory(const CompressionFactory&) = delete;
+            CompressionFactory& operator=(const CompressionFactory&) = delete;
+
+            CompressionFactory(CompressionFactory&&) = delete;
+            CompressionFactory& operator=(CompressionFactory&&) = delete;
+
+            OSMIUM_NORETURN void error(osmium::io::file_compression compression) {
+                std::string error_message {"Support for compression '"};
+                error_message += as_string(compression);
+                error_message += "' not compiled into this binary.";
+                throw unsupported_file_format_error(error_message);
+            }
+
+        public:
+
+            static CompressionFactory& instance() {
+                static CompressionFactory factory;
+                return factory;
+            }
+
+            bool register_compression(
+                osmium::io::file_compression compression,
+                create_compressor_type create_compressor,
+                create_decompressor_type_fd create_decompressor_fd,
+                create_decompressor_type_buffer create_decompressor_buffer) {
+
+                compression_map_type::value_type cc(compression,
+                                                    std::make_tuple(create_compressor,
+                                                                    create_decompressor_fd,
+                                                                    create_decompressor_buffer));
+
+                return m_callbacks.insert(cc).second;
+            }
+
+            template <typename... TArgs>
+            std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, TArgs&&... args) {
+                auto it = m_callbacks.find(compression);
+
+                if (it != m_callbacks.end()) {
+                    return std::unique_ptr<osmium::io::Compressor>(std::get<0>(it->second)(std::forward<TArgs>(args)...));
+                }
+
+                error(compression);
+            }
+
+            std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, int fd) {
+                auto it = m_callbacks.find(compression);
+
+                if (it != m_callbacks.end()) {
+                    return std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
+                }
+
+                error(compression);
+            }
+
+            std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, size_t size) {
+                auto it = m_callbacks.find(compression);
+
+                if (it != m_callbacks.end()) {
+                    return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(it->second)(buffer, size));
+                }
+
+                error(compression);
+            }
+
+        }; // class CompressionFactory
+
+        class NoCompressor : public Compressor {
+
+            int m_fd;
+
+        public:
+
+            NoCompressor(int fd, fsync sync) :
+                Compressor(sync),
+                m_fd(fd) {
+            }
+
+            ~NoCompressor() noexcept override final {
+                try {
+                    close();
+                } catch (...) {
+                    // Ignore any exceptions because destructor must not throw.
+                }
+            }
+
+            void write(const std::string& data) override final {
+                osmium::io::detail::reliable_write(m_fd, data.data(), data.size());
+            }
+
+            void close() override final {
+                if (m_fd >= 0) {
+                    int fd = m_fd;
+                    m_fd = -1;
+                    if (do_fsync()) {
+                        osmium::io::detail::reliable_fsync(fd);
+                    }
+                    osmium::io::detail::reliable_close(fd);
+                }
+            }
+
+        }; // class NoCompressor
+
+        class NoDecompressor : public Decompressor {
+
+            int m_fd;
+            const char *m_buffer;
+            size_t m_buffer_size;
+
+        public:
+
+            NoDecompressor(int fd) :
+                Decompressor(),
+                m_fd(fd),
+                m_buffer(nullptr),
+                m_buffer_size(0) {
+            }
+
+            NoDecompressor(const char* buffer, size_t size) :
+                Decompressor(),
+                m_fd(-1),
+                m_buffer(buffer),
+                m_buffer_size(size) {
+            }
+
+            ~NoDecompressor() noexcept override final {
+                try {
+                    close();
+                } catch (...) {
+                    // Ignore any exceptions because destructor must not throw.
+                }
+            }
+
+            std::string read() override final {
+                std::string buffer;
+
+                if (m_buffer) {
+                    if (m_buffer_size != 0) {
+                        size_t size = m_buffer_size;
+                        m_buffer_size = 0;
+                        buffer.append(m_buffer, size);
+                    }
+                } else {
+                    buffer.resize(osmium::io::Decompressor::input_buffer_size);
+                    auto nread = ::read(m_fd, const_cast<char*>(buffer.data()), osmium::io::Decompressor::input_buffer_size);
+                    if (nread < 0) {
+                        throw std::system_error(errno, std::system_category(), "Read failed");
+                    }
+                    buffer.resize(std::string::size_type(nread));
+                }
+
+                return buffer;
+            }
+
+            void close() override final {
+                if (m_fd >= 0) {
+                    int fd = m_fd;
+                    m_fd = -1;
+                    osmium::io::detail::reliable_close(fd);
+                }
+            }
+
+        }; // class NoDecompressor
+
+        namespace detail {
+
+            // we want the register_compression() function to run, setting
+            // the variable is only a side-effect, it will never be used
+            const bool registered_no_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::none,
+                [](int fd, fsync sync) { return new osmium::io::NoCompressor(fd, sync); },
+                [](int fd) { return new osmium::io::NoDecompressor(fd); },
+                [](const char* buffer, size_t size) { return new osmium::io::NoDecompressor(buffer, size); }
+            );
+
+            // dummy function to silence the unused variable warning from above
+            inline bool get_registered_no_compression() noexcept {
+                return registered_no_compression;
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_COMPRESSION_HPP
diff --git a/contrib/libosmium/osmium/io/debug_output.hpp b/contrib/libosmium/osmium/io/debug_output.hpp
new file mode 100644
index 0000000..2836f79
--- /dev/null
+++ b/contrib/libosmium/osmium/io/debug_output.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_DEBUG_OUTPUT_HPP
+#define OSMIUM_IO_DEBUG_OUTPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/io/writer.hpp> // IWYU pragma: export
+#include <osmium/io/detail/debug_output_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_DEBUG_OUTPUT_HPP
diff --git a/contrib/libosmium/osmium/io/detail/debug_output_format.hpp b/contrib/libosmium/osmium/io/detail/debug_output_format.hpp
new file mode 100644
index 0000000..90ec199
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/debug_output_format.hpp
@@ -0,0 +1,485 @@
+#ifndef OSMIUM_IO_DETAIL_DEBUG_OUTPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_DEBUG_OUTPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cinttypes>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <future>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/changeset.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/thread/pool.hpp>
+#include <osmium/util/minmax.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        class File;
+
+        namespace detail {
+
+            constexpr const char* color_bold    = "\x1b[1m";
+            constexpr const char* color_black   = "\x1b[30m";
+            constexpr const char* color_gray    = "\x1b[30;1m";
+            constexpr const char* color_red     = "\x1b[31m";
+            constexpr const char* color_green   = "\x1b[32m";
+            constexpr const char* color_yellow  = "\x1b[33m";
+            constexpr const char* color_blue    = "\x1b[34m";
+            constexpr const char* color_magenta = "\x1b[35m";
+            constexpr const char* color_cyan    = "\x1b[36m";
+            constexpr const char* color_white   = "\x1b[37m";
+            constexpr const char* color_reset   = "\x1b[0m";
+
+            struct debug_output_options {
+
+                /// Should metadata of objects be added?
+                bool add_metadata;
+
+                /// Output with ANSI colors?
+                bool use_color;
+
+            };
+
+            /**
+             * Writes out one buffer with OSM data in Debug format.
+             */
+            class DebugOutputBlock : public OutputBlock {
+
+                debug_output_options m_options;
+
+                const char* m_utf8_prefix = "";
+                const char* m_utf8_suffix = "";
+
+                void append_encoded_string(const char* data) {
+                    append_debug_encoded_string(*m_out, data, m_utf8_prefix, m_utf8_suffix);
+                }
+
+                void write_color(const char* color) {
+                    if (m_options.use_color) {
+                        *m_out += color;
+                    }
+                }
+
+                void write_string(const char* string) {
+                    *m_out += '"';
+                    write_color(color_blue);
+                    append_encoded_string(string);
+                    write_color(color_reset);
+                    *m_out += '"';
+                }
+
+                void write_object_type(const char* object_type, bool visible = true) {
+                    if (visible) {
+                        write_color(color_bold);
+                    } else {
+                        write_color(color_white);
+                    }
+                    *m_out += object_type;
+                    write_color(color_reset);
+                    *m_out += ' ';
+                }
+
+                void write_fieldname(const char* name) {
+                    *m_out += "  ";
+                    write_color(color_cyan);
+                    *m_out += name;
+                    write_color(color_reset);
+                    *m_out += ": ";
+                }
+
+                void write_comment_field(const char* name) {
+                    write_color(color_cyan);
+                    *m_out += name;
+                    write_color(color_reset);
+                    *m_out += ": ";
+                }
+
+                void write_counter(int width, int n) {
+                    write_color(color_white);
+                    output_formatted("    %0*d: ", width, n++);
+                    write_color(color_reset);
+                }
+
+                void write_error(const char* msg) {
+                    write_color(color_red);
+                    *m_out += msg;
+                    write_color(color_reset);
+                }
+
+                void write_timestamp(const osmium::Timestamp& timestamp) {
+                    if (timestamp.valid()) {
+                        *m_out += timestamp.to_iso();
+                        output_formatted(" (%d)", timestamp.seconds_since_epoch());
+                    } else {
+                        write_error("NOT SET");
+                    }
+                    *m_out += '\n';
+                }
+
+                void write_meta(const osmium::OSMObject& object) {
+                    output_formatted("%" PRId64 "\n", object.id());
+                    if (m_options.add_metadata) {
+                        write_fieldname("version");
+                        output_formatted("  %d", object.version());
+                        if (object.visible()) {
+                            *m_out += " visible\n";
+                        } else {
+                            write_error(" deleted\n");
+                        }
+                        write_fieldname("changeset");
+                        output_formatted("%d\n", object.changeset());
+                        write_fieldname("timestamp");
+                        write_timestamp(object.timestamp());
+                        write_fieldname("user");
+                        output_formatted("     %d ", object.uid());
+                        write_string(object.user());
+                        *m_out += '\n';
+                    }
+                }
+
+                void write_tags(const osmium::TagList& tags, const char* padding="") {
+                    if (!tags.empty()) {
+                        write_fieldname("tags");
+                        *m_out += padding;
+                        output_formatted("     %d\n", tags.size());
+
+                        osmium::max_op<size_t> max;
+                        for (const auto& tag : tags) {
+                            max.update(std::strlen(tag.key()));
+                        }
+                        for (const auto& tag : tags) {
+                            *m_out += "    ";
+                            write_string(tag.key());
+                            auto spacing = max() - std::strlen(tag.key());
+                            while (spacing--) {
+                                *m_out += " ";
+                            }
+                            *m_out += " = ";
+                            write_string(tag.value());
+                            *m_out += '\n';
+                        }
+                    }
+                }
+
+                void write_location(const osmium::Location& location) {
+                    write_fieldname("lon/lat");
+                    output_formatted("  %.7f,%.7f", location.lon_without_check(), location.lat_without_check());
+                    if (!location.valid()) {
+                        write_error(" INVALID LOCATION!");
+                    }
+                    *m_out += '\n';
+                }
+
+                void write_box(const osmium::Box& box) {
+                    write_fieldname("box l/b/r/t");
+                    if (!box) {
+                        write_error("BOX NOT SET!\n");
+                        return;
+                    }
+                    const auto& bl = box.bottom_left();
+                    const auto& tr = box.top_right();
+                    output_formatted("%.7f,%.7f %.7f,%.7f", bl.lon_without_check(), bl.lat_without_check(), tr.lon_without_check(), tr.lat_without_check());
+                    if (!box.valid()) {
+                        write_error(" INVALID BOX!");
+                    }
+                    *m_out += '\n';
+                }
+
+            public:
+
+                DebugOutputBlock(osmium::memory::Buffer&& buffer, const debug_output_options& options) :
+                    OutputBlock(std::move(buffer)),
+                    m_options(options),
+                    m_utf8_prefix(options.use_color ? color_red  : ""),
+                    m_utf8_suffix(options.use_color ? color_blue : "") {
+                }
+
+                DebugOutputBlock(const DebugOutputBlock&) = default;
+                DebugOutputBlock& operator=(const DebugOutputBlock&) = default;
+
+                DebugOutputBlock(DebugOutputBlock&&) = default;
+                DebugOutputBlock& operator=(DebugOutputBlock&&) = default;
+
+                ~DebugOutputBlock() noexcept = default;
+
+                std::string operator()() {
+                    osmium::apply(m_input_buffer->cbegin(), m_input_buffer->cend(), *this);
+
+                    std::string out;
+                    using std::swap;
+                    swap(out, *m_out);
+
+                    return out;
+                }
+
+                void node(const osmium::Node& node) {
+                    write_object_type("node", node.visible());
+                    write_meta(node);
+
+                    if (node.visible()) {
+                        write_location(node.location());
+                    }
+
+                    write_tags(node.tags());
+
+                    *m_out += '\n';
+                }
+
+                void way(const osmium::Way& way) {
+                    write_object_type("way", way.visible());
+                    write_meta(way);
+                    write_tags(way.tags());
+
+                    write_fieldname("nodes");
+
+                    output_formatted("    %d", way.nodes().size());
+                    if (way.nodes().size() < 2) {
+                        write_error(" LESS THAN 2 NODES!\n");
+                    } else if (way.nodes().size() > 2000) {
+                        write_error(" MORE THAN 2000 NODES!\n");
+                    } else if (way.nodes().is_closed()) {
+                        *m_out += " (closed)\n";
+                    } else {
+                        *m_out += " (open)\n";
+                    }
+
+                    int width = int(log10(way.nodes().size())) + 1;
+                    int n = 0;
+                    for (const auto& node_ref : way.nodes()) {
+                        write_counter(width, n++);
+                        output_formatted("%10" PRId64, node_ref.ref());
+                        if (node_ref.location().valid()) {
+                            output_formatted(" (%.7f,%.7f)", node_ref.location().lon_without_check(), node_ref.location().lat_without_check());
+                        }
+                        *m_out += '\n';
+                    }
+
+                    *m_out += '\n';
+                }
+
+                void relation(const osmium::Relation& relation) {
+                    static const char* short_typename[] = { "node", "way ", "rel " };
+                    write_object_type("relation", relation.visible());
+                    write_meta(relation);
+                    write_tags(relation.tags());
+
+                    write_fieldname("members");
+                    output_formatted("  %d\n", relation.members().size());
+
+                    int width = int(log10(relation.members().size())) + 1;
+                    int n = 0;
+                    for (const auto& member : relation.members()) {
+                        write_counter(width, n++);
+                        *m_out += short_typename[item_type_to_nwr_index(member.type())];
+                        output_formatted(" %10" PRId64 " ", member.ref());
+                        write_string(member.role());
+                        *m_out += '\n';
+                    }
+
+                    *m_out += '\n';
+                }
+
+                void changeset(const osmium::Changeset& changeset) {
+                    write_object_type("changeset");
+                    output_formatted("%d\n", changeset.id());
+
+                    write_fieldname("num changes");
+                    output_formatted("%d", changeset.num_changes());
+                    if (changeset.num_changes() == 0) {
+                        write_error(" NO CHANGES!");
+                    }
+                    *m_out += '\n';
+
+                    write_fieldname("created at");
+                    *m_out += ' ';
+                    write_timestamp(changeset.created_at());
+
+                    write_fieldname("closed at");
+                    *m_out += "  ";
+                    if (changeset.closed()) {
+                        write_timestamp(changeset.closed_at());
+                    } else {
+                        write_error("OPEN!\n");
+                    }
+
+                    write_fieldname("user");
+                    output_formatted("       %d ", changeset.uid());
+                    write_string(changeset.user());
+                    *m_out += '\n';
+
+                    write_box(changeset.bounds());
+                    write_tags(changeset.tags(), "  ");
+
+                    if (changeset.num_comments() > 0) {
+                        write_fieldname("comments");
+                        output_formatted("   %d\n", changeset.num_comments());
+
+                        int width = int(log10(changeset.num_comments())) + 1;
+                        int n = 0;
+                        for (const auto& comment : changeset.discussion()) {
+                            write_counter(width, n++);
+
+                            write_comment_field("date");
+                            write_timestamp(comment.date());
+                            output_formatted("      %*s", width, "");
+
+                            write_comment_field("user");
+                            output_formatted("%d ", comment.uid());
+                            write_string(comment.user());
+                            output_formatted("\n      %*s", width, "");
+
+                            write_comment_field("text");
+                            write_string(comment.text());
+                            *m_out += '\n';
+                        }
+                    }
+
+                    *m_out += '\n';
+                }
+
+            }; // class DebugOutputBlock
+
+            class DebugOutputFormat : public osmium::io::detail::OutputFormat {
+
+                debug_output_options m_options;
+
+                void write_fieldname(std::string& out, const char* name) {
+                    out += "  ";
+                    if (m_options.use_color) {
+                        out += color_cyan;
+                    }
+                    out += name;
+                    if (m_options.use_color) {
+                        out += color_reset;
+                    }
+                    out += ": ";
+                }
+
+            public:
+
+                DebugOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
+                    OutputFormat(output_queue),
+                    m_options() {
+                    m_options.add_metadata = file.is_not_false("add_metadata");
+                    m_options.use_color    = file.is_true("color");
+                }
+
+                DebugOutputFormat(const DebugOutputFormat&) = delete;
+                DebugOutputFormat& operator=(const DebugOutputFormat&) = delete;
+
+                ~DebugOutputFormat() noexcept = default;
+
+                void write_header(const osmium::io::Header& header) override final {
+                    std::string out;
+
+                    if (m_options.use_color) {
+                        out += color_bold;
+                    }
+                    out += "header\n";
+                    if (m_options.use_color) {
+                        out += color_reset;
+                    }
+
+                    write_fieldname(out, "multiple object versions");
+                    out += header.has_multiple_object_versions() ? "yes" : "no";
+                    out += '\n';
+                    write_fieldname(out, "bounding boxes");
+                    out += '\n';
+                    for (const auto& box : header.boxes()) {
+                        out += "    ";
+                        box.bottom_left().as_string(std::back_inserter(out), ',');
+                        out += " ";
+                        box.top_right().as_string(std::back_inserter(out), ',');
+                        out += '\n';
+                    }
+                    write_fieldname(out, "options");
+                    out += '\n';
+                    for (const auto& opt : header) {
+                        out += "    ";
+                        out += opt.first;
+                        out += " = ";
+                        out += opt.second;
+                        out += '\n';
+                    }
+                    out += "\n=============================================\n\n";
+
+                    send_to_output_queue(std::move(out));
+                }
+
+                void write_buffer(osmium::memory::Buffer&& buffer) override final {
+                    m_output_queue.push(osmium::thread::Pool::instance().submit(DebugOutputBlock{std::move(buffer), m_options}));
+                }
+
+            }; // class DebugOutputFormat
+
+            // we want the register_output_format() function to run, setting
+            // the variable is only a side-effect, it will never be used
+            const bool registered_debug_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::debug,
+                [](const osmium::io::File& file, future_string_queue_type& output_queue) {
+                    return new osmium::io::detail::DebugOutputFormat(file, output_queue);
+            });
+
+            // dummy function to silence the unused variable warning from above
+            inline bool get_registered_debug_output() noexcept {
+                return registered_debug_output;
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_DEBUG_OUTPUT_FORMAT_HPP
diff --git a/contrib/libosmium/osmium/io/detail/input_format.hpp b/contrib/libosmium/osmium/io/detail/input_format.hpp
new file mode 100644
index 0000000..d26b1ee
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/input_format.hpp
@@ -0,0 +1,211 @@
+#ifndef OSMIUM_IO_DETAIL_INPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_INPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <exception>
+#include <functional>
+#include <future>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include <osmium/io/detail/queue_util.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/entity_bits.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            class Parser {
+
+                future_buffer_queue_type& m_output_queue;
+                std::promise<osmium::io::Header>& m_header_promise;
+                queue_wrapper<std::string> m_input_queue;
+                osmium::osm_entity_bits::type m_read_types;
+                bool m_header_is_done;
+
+            protected:
+
+                std::string get_input() {
+                    return m_input_queue.pop();
+                }
+
+                bool input_done() const {
+                    return m_input_queue.has_reached_end_of_data();
+                }
+
+                osmium::osm_entity_bits::type read_types() const {
+                    return m_read_types;
+                }
+
+                bool header_is_done() const {
+                    return m_header_is_done;
+                }
+
+                void set_header_value(const osmium::io::Header& header) {
+                    if (!m_header_is_done) {
+                        m_header_is_done = true;
+                        m_header_promise.set_value(header);
+                    }
+                }
+
+                void set_header_exception(const std::exception_ptr& exception) {
+                    if (!m_header_is_done) {
+                        m_header_is_done = true;
+                        m_header_promise.set_exception(exception);
+                    }
+                }
+
+                /**
+                 * Wrap the buffer into a future and add it to the output queue.
+                 */
+                void send_to_output_queue(osmium::memory::Buffer&& buffer) {
+                    add_to_queue(m_output_queue, std::move(buffer));
+                }
+
+                void send_to_output_queue(std::future<osmium::memory::Buffer>&& future) {
+                    m_output_queue.push(std::move(future));
+                }
+
+            public:
+
+                Parser(future_string_queue_type& input_queue,
+                       future_buffer_queue_type& output_queue,
+                       std::promise<osmium::io::Header>& header_promise,
+                       osmium::osm_entity_bits::type read_types) :
+                    m_output_queue(output_queue),
+                    m_header_promise(header_promise),
+                    m_input_queue(input_queue),
+                    m_read_types(read_types),
+                    m_header_is_done(false) {
+                }
+
+                Parser(const Parser&) = delete;
+                Parser& operator=(const Parser&) = delete;
+
+                Parser(Parser&&) = delete;
+                Parser& operator=(Parser&&) = delete;
+
+                virtual ~Parser() noexcept = default;
+
+                virtual void run() = 0;
+
+                void parse() {
+                    try {
+                        run();
+                    } catch (...) {
+                        std::exception_ptr exception = std::current_exception();
+                        set_header_exception(exception);
+                        add_to_queue(m_output_queue, std::move(exception));
+                    }
+
+                    add_end_of_data_to_queue(m_output_queue);
+                }
+
+            }; // class Parser
+
+            /**
+             * This factory class is used to create objects that decode OSM
+             * data written in a specified format.
+             *
+             * Do not use this class directly. Use the osmium::io::Reader
+             * class instead.
+             */
+            class ParserFactory {
+
+            public:
+
+                typedef std::function<
+                            std::unique_ptr<Parser>(
+                                future_string_queue_type&,
+                                future_buffer_queue_type&,
+                                std::promise<osmium::io::Header>& header_promise,
+                                osmium::osm_entity_bits::type read_which_entities
+                            )
+                        > create_parser_type;
+
+            private:
+
+                typedef std::map<osmium::io::file_format, create_parser_type> map_type;
+
+                map_type m_callbacks;
+
+                ParserFactory() :
+                    m_callbacks() {
+                }
+
+            public:
+
+                static ParserFactory& instance() {
+                    static ParserFactory factory;
+                    return factory;
+                }
+
+                bool register_parser(osmium::io::file_format format, create_parser_type create_function) {
+                    if (! m_callbacks.insert(map_type::value_type(format, create_function)).second) {
+                        return false;
+                    }
+                    return true;
+                }
+
+                create_parser_type get_creator_function(const osmium::io::File& file) {
+                    auto it = m_callbacks.find(file.format());
+                    if (it == m_callbacks.end()) {
+                        throw unsupported_file_format_error(
+                                std::string("Can not open file '") +
+                                file.filename() +
+                                "' with type '" +
+                                as_string(file.format()) +
+                                "'. No support for reading this format in this program.");
+                    }
+                    return it->second;
+                }
+
+            }; // class ParserFactory
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_INPUT_FORMAT_HPP
diff --git a/contrib/libosmium/osmium/io/detail/o5m_input_format.hpp b/contrib/libosmium/osmium/io/detail/o5m_input_format.hpp
new file mode 100644
index 0000000..b5b5c71
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/o5m_input_format.hpp
@@ -0,0 +1,633 @@
+#ifndef OSMIUM_IO_DETAIL_O5M_INPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_O5M_INPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <future>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <protozero/varint.hpp>
+
+#include <osmium/builder/builder.hpp>
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/io/detail/input_format.hpp>
+#include <osmium/io/detail/queue_util.hpp>
+#include <osmium/io/error.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/util/delta.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when the o5m deocder failed. The exception contains
+     * (if available) information about the place where the error happened
+     * and the type of error.
+     */
+    struct o5m_error : public io_error {
+
+        o5m_error(const char* what) :
+            io_error(std::string("o5m format error: ") + what) {
+        }
+
+    }; // struct o5m_error
+
+    namespace io {
+
+        namespace detail {
+
+            // Implementation of the o5m/o5c file formats according to the
+            // description at http://wiki.openstreetmap.org/wiki/O5m .
+
+            class ReferenceTable {
+
+                // The following settings are from the o5m description:
+
+                // The maximum number of entries in this table.
+                const uint64_t number_of_entries = 15000;
+
+                // The size of one entry in the table.
+                const unsigned int entry_size = 256;
+
+                // The maximum length of a string in the table including
+                // two \0 bytes.
+                const unsigned int max_length = 250 + 2;
+
+                // The data is stored in this string. It is default constructed
+                // and then resized on demand the first time something is added.
+                // This is done because the ReferenceTable is in a O5mParser
+                // object which will be copied from one thread to another. This
+                // way the string is still small when it is copied.
+                std::string m_table;
+
+                unsigned int current_entry = 0;
+
+            public:
+
+                void clear() {
+                    current_entry = 0;
+                }
+
+                void add(const char* string, size_t size) {
+                    if (m_table.empty()) {
+                        m_table.resize(entry_size * number_of_entries);
+                    }
+                    if (size <= max_length) {
+                        std::copy_n(string, size, &m_table[current_entry * entry_size]);
+                        if (++current_entry == number_of_entries) {
+                            current_entry = 0;
+                        }
+                    }
+                }
+
+                const char* get(uint64_t index) const {
+                    if (m_table.empty() || index == 0 || index > number_of_entries) {
+                        throw o5m_error("reference to non-existing string in table");
+                    }
+                    auto entry = (current_entry + number_of_entries - index) % number_of_entries;
+                    return &m_table[entry * entry_size];
+                }
+
+            }; // class ReferenceTable
+
+            class O5mParser : public Parser {
+
+                static constexpr int buffer_size = 2 * 1000 * 1000;
+
+                osmium::io::Header m_header;
+
+                osmium::memory::Buffer m_buffer;
+
+                std::string m_input;
+
+                const char* m_data;
+                const char* m_end;
+
+                ReferenceTable m_reference_table;
+
+                static int64_t zvarint(const char** data, const char* end) {
+                    return protozero::decode_zigzag64(protozero::decode_varint(data, end));
+                }
+
+                bool ensure_bytes_available(size_t need_bytes) {
+                    if ((m_end - m_data) >= long(need_bytes)) {
+                        return true;
+                    }
+
+                    if (input_done() && (m_input.size() < need_bytes)) {
+                        return false;
+                    }
+
+                    m_input.erase(0, m_data - m_input.data());
+
+                    while (m_input.size() < need_bytes) {
+                        std::string data = get_input();
+                        if (input_done()) {
+                            return false;
+                        }
+                        m_input.append(data);
+                    }
+
+                    m_data = m_input.data();
+                    m_end = m_input.data() + m_input.size();
+
+                    return true;
+                }
+
+                void check_header_magic() {
+                    static const unsigned char header_magic[] = { 0xff, 0xe0, 0x04, 'o', '5' };
+
+                    if (std::strncmp(reinterpret_cast<const char*>(header_magic), m_data, sizeof(header_magic))) {
+                        throw o5m_error("wrong header magic");
+                    }
+
+                    m_data += sizeof(header_magic);
+                }
+
+                void check_file_type() {
+                    if (*m_data == 'm') {         // o5m data file
+                        m_header.set_has_multiple_object_versions(false);
+                    } else if (*m_data == 'c') {  // o5c change file
+                        m_header.set_has_multiple_object_versions(true);
+                    } else {
+                        throw o5m_error("wrong header magic");
+                    }
+
+                    m_data++;
+                }
+
+                void check_file_format_version() {
+                    if (*m_data != '2') {
+                        throw o5m_error("wrong header magic");
+                    }
+
+                    m_data++;
+                }
+
+                void decode_header() {
+                    if (! ensure_bytes_available(7)) { // overall length of header
+                        throw o5m_error("file too short (incomplete header info)");
+                    }
+
+                    check_header_magic();
+                    check_file_type();
+                    check_file_format_version();
+                }
+
+                void mark_header_as_done() {
+                    set_header_value(m_header);
+                }
+
+                osmium::util::DeltaDecode<osmium::object_id_type> m_delta_id;
+
+                osmium::util::DeltaDecode<int64_t> m_delta_timestamp;
+                osmium::util::DeltaDecode<osmium::changeset_id_type> m_delta_changeset;
+                osmium::util::DeltaDecode<int64_t> m_delta_lon;
+                osmium::util::DeltaDecode<int64_t> m_delta_lat;
+
+                osmium::util::DeltaDecode<osmium::object_id_type> m_delta_way_node_id;
+                osmium::util::DeltaDecode<osmium::object_id_type> m_delta_member_ids[3];
+
+                void reset() {
+                    m_reference_table.clear();
+
+                    m_delta_id.clear();
+                    m_delta_timestamp.clear();
+                    m_delta_changeset.clear();
+                    m_delta_lon.clear();
+                    m_delta_lat.clear();
+
+                    m_delta_way_node_id.clear();
+                    m_delta_member_ids[0].clear();
+                    m_delta_member_ids[1].clear();
+                    m_delta_member_ids[2].clear();
+                }
+
+                const char* decode_string(const char** dataptr, const char* const end) {
+                    if (**dataptr == 0x00) { // get inline string
+                        (*dataptr)++;
+                        if (*dataptr == end) {
+                            throw o5m_error("string format error");
+                        }
+                        return *dataptr;
+                    } else { // get from reference table
+                        auto index = protozero::decode_varint(dataptr, end);
+                        return m_reference_table.get(index);
+                    }
+                }
+
+                std::pair<osmium::user_id_type, const char*> decode_user(const char** dataptr, const char* const end) {
+                    bool update_pointer = (**dataptr == 0x00);
+                    const char* data = decode_string(dataptr, end);
+                    const char* start = data;
+
+                    auto uid = protozero::decode_varint(&data, end);
+
+                    if (data == end) {
+                        throw o5m_error("missing user name");
+                    }
+
+                    const char* user = ++data;
+
+                    if (uid == 0 && update_pointer) {
+                        m_reference_table.add("\0\0", 2);
+                        *dataptr = data;
+                        return std::make_pair(0, "");
+                    }
+
+                    while (*data++) {
+                        if (data == end) {
+                            throw o5m_error("no null byte in user name");
+                        }
+                    }
+
+                    if (update_pointer) {
+                        m_reference_table.add(start, data - start);
+                        *dataptr = data;
+                    }
+
+                    return std::make_pair(static_cast_with_assert<osmium::user_id_type>(uid), user);
+                }
+
+                void decode_tags(osmium::builder::Builder* builder, const char** dataptr, const char* const end) {
+                    osmium::builder::TagListBuilder tl_builder(m_buffer, builder);
+
+                    while(*dataptr != end) {
+                        bool update_pointer = (**dataptr == 0x00);
+                        const char* data = decode_string(dataptr, end);
+                        const char* start = data;
+
+                        while (*data++) {
+                            if (data == end) {
+                                throw o5m_error("no null byte in tag key");
+                            }
+                        }
+
+                        const char* value = data;
+                        while (*data++) {
+                            if (data == end) {
+                                throw o5m_error("no null byte in tag value");
+                            }
+                        }
+
+                        if (update_pointer) {
+                            m_reference_table.add(start, data - start);
+                            *dataptr = data;
+                        }
+
+                        tl_builder.add_tag(start, value);
+                    }
+                }
+
+                const char* decode_info(osmium::OSMObject& object, const char** dataptr, const char* const end) {
+                    const char* user = "";
+
+                    if (**dataptr == 0x00) { // no info section
+                        ++*dataptr;
+                    } else { // has info section
+                        object.set_version(static_cast_with_assert<object_version_type>(protozero::decode_varint(dataptr, end)));
+                        auto timestamp = m_delta_timestamp.update(zvarint(dataptr, end));
+                        if (timestamp != 0) { // has timestamp
+                            object.set_timestamp(timestamp);
+                            object.set_changeset(m_delta_changeset.update(zvarint(dataptr, end)));
+                            if (*dataptr != end) {
+                                auto uid_user = decode_user(dataptr, end);
+                                object.set_uid(uid_user.first);
+                                user = uid_user.second;
+                            } else {
+                                object.set_uid(user_id_type(0));
+                            }
+                        }
+                    }
+
+                    return user;
+                }
+
+                void decode_node(const char* data, const char* const end) {
+                    osmium::builder::NodeBuilder builder(m_buffer);
+                    osmium::Node& node = builder.object();
+
+                    node.set_id(m_delta_id.update(zvarint(&data, end)));
+
+                    builder.add_user(decode_info(node, &data, end));
+
+                    if (data == end) {
+                        // no location, object is deleted
+                        builder.object().set_visible(false);
+                        builder.object().set_location(osmium::Location{});
+                    } else {
+                        auto lon = m_delta_lon.update(zvarint(&data, end));
+                        auto lat = m_delta_lat.update(zvarint(&data, end));
+                        builder.object().set_location(osmium::Location{lon, lat});
+
+                        if (data != end) {
+                            decode_tags(&builder, &data, end);
+                        }
+                    }
+
+                    m_buffer.commit();
+                }
+
+                void decode_way(const char* data, const char* const end) {
+                    osmium::builder::WayBuilder builder(m_buffer);
+                    osmium::Way& way = builder.object();
+
+                    way.set_id(m_delta_id.update(zvarint(&data, end)));
+
+                    builder.add_user(decode_info(way, &data, end));
+
+                    if (data == end) {
+                        // no reference section, object is deleted
+                        builder.object().set_visible(false);
+                    } else {
+                        auto reference_section_length = protozero::decode_varint(&data, end);
+                        if (reference_section_length > 0) {
+                            const char* const end_refs = data + reference_section_length;
+                            if (end_refs > end) {
+                                throw o5m_error("way nodes ref section too long");
+                            }
+
+                            osmium::builder::WayNodeListBuilder wn_builder(m_buffer, &builder);
+
+                            while (data < end_refs) {
+                                wn_builder.add_node_ref(m_delta_way_node_id.update(zvarint(&data, end)));
+                            }
+                        }
+
+                        if (data != end) {
+                            decode_tags(&builder, &data, end);
+                        }
+                    }
+
+                    m_buffer.commit();
+                }
+
+                osmium::item_type decode_member_type(char c) {
+                    if (c < '0' || c > '2') {
+                        throw o5m_error("unknown member type");
+                    }
+                    return osmium::nwr_index_to_item_type(c - '0');
+                }
+
+                std::pair<osmium::item_type, const char*> decode_role(const char** dataptr, const char* const end) {
+                    bool update_pointer = (**dataptr == 0x00);
+                    const char* data = decode_string(dataptr, end);
+                    const char* start = data;
+
+                    auto member_type = decode_member_type(*data++);
+                    if (data == end) {
+                        throw o5m_error("missing role");
+                    }
+                    const char* role = data;
+
+                    while (*data++) {
+                        if (data == end) {
+                            throw o5m_error("no null byte in role");
+                        }
+                    }
+
+                    if (update_pointer) {
+                        m_reference_table.add(start, data - start);
+                        *dataptr = data;
+                    }
+
+                    return std::make_pair(member_type, role);
+                }
+
+                void decode_relation(const char* data, const char* const end) {
+                    osmium::builder::RelationBuilder builder(m_buffer);
+                    osmium::Relation& relation = builder.object();
+
+                    relation.set_id(m_delta_id.update(zvarint(&data, end)));
+
+                    builder.add_user(decode_info(relation, &data, end));
+
+                    if (data == end) {
+                        // no reference section, object is deleted
+                        builder.object().set_visible(false);
+                    } else {
+                        auto reference_section_length = protozero::decode_varint(&data, end);
+                        if (reference_section_length > 0) {
+                            const char* const end_refs = data + reference_section_length;
+                            if (end_refs > end) {
+                                throw o5m_error("relation format error");
+                            }
+
+                            osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
+
+                            while (data < end_refs) {
+                                auto delta_id = zvarint(&data, end);
+                                if (data == end) {
+                                    throw o5m_error("relation member format error");
+                                }
+                                auto type_role = decode_role(&data, end);
+                                auto i = osmium::item_type_to_nwr_index(type_role.first);
+                                auto ref = m_delta_member_ids[i].update(delta_id);
+                                rml_builder.add_member(type_role.first, ref, type_role.second);
+                            }
+                        }
+
+                        if (data != end) {
+                            decode_tags(&builder, &data, end);
+                        }
+                    }
+
+                    m_buffer.commit();
+                }
+
+                void decode_bbox(const char* data, const char* const end) {
+                    auto sw_lon = zvarint(&data, end);
+                    auto sw_lat = zvarint(&data, end);
+                    auto ne_lon = zvarint(&data, end);
+                    auto ne_lat = zvarint(&data, end);
+
+                    m_header.add_box(osmium::Box{osmium::Location{sw_lon, sw_lat},
+                                                 osmium::Location{ne_lon, ne_lat}});
+                }
+
+                void decode_timestamp(const char* data, const char* const end) {
+                    auto timestamp = osmium::Timestamp(zvarint(&data, end)).to_iso();
+                    m_header.set("o5m_timestamp", timestamp);
+                    m_header.set("timestamp", timestamp);
+                }
+
+                void flush() {
+                    osmium::memory::Buffer buffer(buffer_size);
+                    using std::swap;
+                    swap(m_buffer, buffer);
+                    send_to_output_queue(std::move(buffer));
+                }
+
+                enum class dataset_type : unsigned char {
+                    node         = 0x10,
+                    way          = 0x11,
+                    relation     = 0x12,
+                    bounding_box = 0xdb,
+                    timestamp    = 0xdc,
+                    header       = 0xe0,
+                    sync         = 0xee,
+                    jump         = 0xef,
+                    reset        = 0xff
+                };
+
+                void decode_data() {
+                    while (ensure_bytes_available(1)) {
+                        dataset_type ds_type = dataset_type(*m_data++);
+                        if (ds_type > dataset_type::jump) {
+                            if (ds_type == dataset_type::reset) {
+                                reset();
+                            }
+                        } else {
+                            ensure_bytes_available(protozero::max_varint_length);
+
+                            uint64_t length = 0;
+                            try {
+                                length = protozero::decode_varint(&m_data, m_end);
+                            } catch (protozero::end_of_buffer_exception&) {
+                                throw o5m_error("premature end of file");
+                            }
+
+                            if (! ensure_bytes_available(length)) {
+                                throw o5m_error("premature end of file");
+                            }
+
+                            switch (ds_type) {
+                                case dataset_type::node:
+                                    mark_header_as_done();
+                                    if (read_types() & osmium::osm_entity_bits::node) {
+                                        decode_node(m_data, m_data + length);
+                                    }
+                                    break;
+                                case dataset_type::way:
+                                    mark_header_as_done();
+                                    if (read_types() & osmium::osm_entity_bits::way) {
+                                        decode_way(m_data, m_data + length);
+                                    }
+                                    break;
+                                case dataset_type::relation:
+                                    mark_header_as_done();
+                                    if (read_types() & osmium::osm_entity_bits::relation) {
+                                        decode_relation(m_data, m_data + length);
+                                    }
+                                    break;
+                                case dataset_type::bounding_box:
+                                    decode_bbox(m_data, m_data + length);
+                                    break;
+                                case dataset_type::timestamp:
+                                    decode_timestamp(m_data, m_data + length);
+                                    break;
+                                default:
+                                    // ignore unknown datasets
+                                    break;
+                            }
+
+                            if (read_types() == osmium::osm_entity_bits::nothing && header_is_done()) {
+                                break;
+                            }
+
+                            m_data += length;
+
+                            if (m_buffer.committed() > buffer_size / 10 * 9) {
+                                flush();
+                            }
+                        }
+                    }
+
+                    if (m_buffer.committed()) {
+                        flush();
+                    }
+
+                    mark_header_as_done();
+                }
+
+            public:
+
+                O5mParser(future_string_queue_type& input_queue,
+                          future_buffer_queue_type& output_queue,
+                          std::promise<osmium::io::Header>& header_promise,
+                          osmium::osm_entity_bits::type read_types) :
+                    Parser(input_queue, output_queue, header_promise, read_types),
+                    m_header(),
+                    m_buffer(buffer_size),
+                    m_input(),
+                    m_data(m_input.data()),
+                    m_end(m_data) {
+                }
+
+                ~O5mParser() noexcept = default;
+
+                void run() override final {
+                    decode_header();
+                    decode_data();
+                }
+
+            }; // class O5mParser
+
+            // we want the register_parser() function to run, setting
+            // the variable is only a side-effect, it will never be used
+            const bool registered_o5m_parser = ParserFactory::instance().register_parser(
+                file_format::o5m,
+                [](future_string_queue_type& input_queue,
+                    future_buffer_queue_type& output_queue,
+                    std::promise<osmium::io::Header>& header_promise,
+                    osmium::osm_entity_bits::type read_which_entities) {
+                    return std::unique_ptr<Parser>(new O5mParser(input_queue, output_queue, header_promise, read_which_entities));
+            });
+
+            // dummy function to silence the unused variable warning from above
+            inline bool get_registered_o5m_parser() noexcept {
+                return registered_o5m_parser;
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_O5M_INPUT_FORMAT_HPP
diff --git a/contrib/libosmium/osmium/io/detail/opl_output_format.hpp b/contrib/libosmium/osmium/io/detail/opl_output_format.hpp
new file mode 100644
index 0000000..5c40bf2
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/opl_output_format.hpp
@@ -0,0 +1,261 @@
+#ifndef OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cinttypes>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <future>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/changeset.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/thread/pool.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        class File;
+
+        namespace detail {
+
+            struct opl_output_options {
+
+                /// Should metadata of objects be added?
+                bool add_metadata;
+
+            };
+
+            /**
+             * Writes out one buffer with OSM data in OPL format.
+             */
+            class OPLOutputBlock : public OutputBlock {
+
+                opl_output_options m_options;
+
+                void append_encoded_string(const char* data) {
+                    osmium::io::detail::append_utf8_encoded_string(*m_out, data);
+                }
+
+                void write_meta(const osmium::OSMObject& object) {
+                    output_formatted("%" PRId64, object.id());
+                    if (m_options.add_metadata) {
+                        output_formatted(" v%d d", object.version());
+                        *m_out += (object.visible() ? 'V' : 'D');
+                        output_formatted(" c%d t", object.changeset());
+                        *m_out += object.timestamp().to_iso();
+                        output_formatted(" i%d u", object.uid());
+                        append_encoded_string(object.user());
+                    }
+                    *m_out += " T";
+                    bool first = true;
+                    for (const auto& tag : object.tags()) {
+                        if (first) {
+                            first = false;
+                        } else {
+                            *m_out += ',';
+                        }
+                        append_encoded_string(tag.key());
+                        *m_out += '=';
+                        append_encoded_string(tag.value());
+                    }
+                }
+
+                void write_location(const osmium::Location& location, const char x, const char y) {
+                    if (location) {
+                        output_formatted(" %c%.7f %c%.7f", x, location.lon_without_check(), y, location.lat_without_check());
+                    } else {
+                        *m_out += ' ';
+                        *m_out += x;
+                        *m_out += ' ';
+                        *m_out += y;
+                    }
+                }
+
+            public:
+
+                OPLOutputBlock(osmium::memory::Buffer&& buffer, const opl_output_options& options) :
+                    OutputBlock(std::move(buffer)),
+                    m_options(options) {
+                }
+
+                OPLOutputBlock(const OPLOutputBlock&) = default;
+                OPLOutputBlock& operator=(const OPLOutputBlock&) = default;
+
+                OPLOutputBlock(OPLOutputBlock&&) = default;
+                OPLOutputBlock& operator=(OPLOutputBlock&&) = default;
+
+                ~OPLOutputBlock() noexcept = default;
+
+                std::string operator()() {
+                    osmium::apply(m_input_buffer->cbegin(), m_input_buffer->cend(), *this);
+
+                    std::string out;
+                    using std::swap;
+                    swap(out, *m_out);
+
+                    return out;
+                }
+
+                void node(const osmium::Node& node) {
+                    *m_out += 'n';
+                    write_meta(node);
+                    write_location(node.location(), 'x', 'y');
+                    *m_out += '\n';
+                }
+
+                void way(const osmium::Way& way) {
+                    *m_out += 'w';
+                    write_meta(way);
+
+                    *m_out += " N";
+                    bool first = true;
+                    for (const auto& node_ref : way.nodes()) {
+                        if (first) {
+                            first = false;
+                        } else {
+                            *m_out += ',';
+                        }
+                        output_formatted("n%" PRId64, node_ref.ref());
+                    }
+                    *m_out += '\n';
+                }
+
+                void relation(const osmium::Relation& relation) {
+                    *m_out += 'r';
+                    write_meta(relation);
+
+                    *m_out += " M";
+                    bool first = true;
+                    for (const auto& member : relation.members()) {
+                        if (first) {
+                            first = false;
+                        } else {
+                            *m_out += ',';
+                        }
+                        *m_out += item_type_to_char(member.type());
+                        output_formatted("%" PRId64 "@", member.ref());
+                        append_encoded_string(member.role());
+                    }
+                    *m_out += '\n';
+                }
+
+                void changeset(const osmium::Changeset& changeset) {
+                    output_formatted("c%d k%d s", changeset.id(), changeset.num_changes());
+                    *m_out += changeset.created_at().to_iso();
+                    *m_out += " e";
+                    *m_out += changeset.closed_at().to_iso();
+                    output_formatted(" d%d i%d u", changeset.num_comments(), changeset.uid());
+                    append_encoded_string(changeset.user());
+                    write_location(changeset.bounds().bottom_left(), 'x', 'y');
+                    write_location(changeset.bounds().top_right(), 'X', 'Y');
+                    *m_out += " T";
+                    bool first = true;
+                    for (const auto& tag : changeset.tags()) {
+                        if (first) {
+                            first = false;
+                        } else {
+                            *m_out += ',';
+                        }
+                        append_encoded_string(tag.key());
+                        *m_out += '=';
+                        append_encoded_string(tag.value());
+                    }
+
+                    *m_out += '\n';
+                }
+
+            }; // class OPLOutputBlock
+
+            class OPLOutputFormat : public osmium::io::detail::OutputFormat {
+
+                opl_output_options m_options;
+
+            public:
+
+                OPLOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
+                    OutputFormat(output_queue),
+                    m_options() {
+                    m_options.add_metadata = file.is_not_false("add_metadata");
+                }
+
+                OPLOutputFormat(const OPLOutputFormat&) = delete;
+                OPLOutputFormat& operator=(const OPLOutputFormat&) = delete;
+
+                ~OPLOutputFormat() noexcept = default;
+
+                void write_buffer(osmium::memory::Buffer&& buffer) override final {
+                    m_output_queue.push(osmium::thread::Pool::instance().submit(OPLOutputBlock{std::move(buffer), m_options}));
+                }
+
+            }; // class OPLOutputFormat
+
+            // we want the register_output_format() function to run, setting
+            // the variable is only a side-effect, it will never be used
+            const bool registered_opl_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::opl,
+                [](const osmium::io::File& file, future_string_queue_type& output_queue) {
+                    return new osmium::io::detail::OPLOutputFormat(file, output_queue);
+            });
+
+            // dummy function to silence the unused variable warning from above
+            inline bool get_registered_opl_output() noexcept {
+                return registered_opl_output;
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
diff --git a/contrib/libosmium/osmium/io/detail/output_format.hpp b/contrib/libosmium/osmium/io/detail/output_format.hpp
new file mode 100644
index 0000000..ba1fb41
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/output_format.hpp
@@ -0,0 +1,184 @@
+#ifndef OSMIUM_IO_DETAIL_OUTPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_OUTPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include <osmium/handler.hpp>
+#include <osmium/io/detail/queue_util.hpp>
+#include <osmium/io/detail/string_util.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/memory/buffer.hpp>
+
+namespace osmium {
+
+    namespace io {
+        class Header;
+    }
+
+    namespace io {
+
+        namespace detail {
+
+            class OutputBlock : public osmium::handler::Handler {
+
+            protected:
+
+                std::shared_ptr<osmium::memory::Buffer> m_input_buffer;
+
+                std::shared_ptr<std::string> m_out;
+
+                explicit OutputBlock(osmium::memory::Buffer&& buffer) :
+                    m_input_buffer(std::make_shared<osmium::memory::Buffer>(std::move(buffer))),
+                    m_out(std::make_shared<std::string>()) {
+                }
+
+                template <typename... TArgs>
+                void output_formatted(const char* format, TArgs&&... args) {
+                    append_printf_formatted_string(*m_out, format, std::forward<TArgs>(args)...);
+                }
+
+            }; // class OutputBlock;
+
+            /**
+             * Virtual base class for all classes writing OSM files in different
+             * formats.
+             *
+             * Do not use this class or derived classes directly. Use the
+             * osmium::io::Writer class instead.
+             */
+            class OutputFormat {
+
+            protected:
+
+                future_string_queue_type& m_output_queue;
+
+                /**
+                 * Wrap the string into a future and add it to the output
+                 * queue.
+                 */
+                void send_to_output_queue(std::string&& data) {
+                    add_to_queue(m_output_queue, std::move(data));
+                }
+
+            public:
+
+                explicit OutputFormat(future_string_queue_type& output_queue) :
+                    m_output_queue(output_queue) {
+                }
+
+                OutputFormat(const OutputFormat&) = delete;
+                OutputFormat(OutputFormat&&) = delete;
+
+                OutputFormat& operator=(const OutputFormat&) = delete;
+                OutputFormat& operator=(OutputFormat&&) = delete;
+
+                virtual ~OutputFormat() noexcept = default;
+
+                virtual void write_header(const osmium::io::Header&) {
+                }
+
+                virtual void write_buffer(osmium::memory::Buffer&&) = 0;
+
+                virtual void write_end() {
+                }
+
+            }; // class OutputFormat
+
+            /**
+             * This factory class is used to create objects that write OSM data
+             * into a specified output format.
+             *
+             * Do not use this class directly. Instead use the osmium::io::Writer
+             * class.
+             */
+            class OutputFormatFactory {
+
+            public:
+
+                typedef std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, future_string_queue_type&)> create_output_type;
+
+            private:
+
+                typedef std::map<osmium::io::file_format, create_output_type> map_type;
+
+                map_type m_callbacks;
+
+                OutputFormatFactory() :
+                    m_callbacks() {
+                }
+
+            public:
+
+                static OutputFormatFactory& instance() {
+                    static OutputFormatFactory factory;
+                    return factory;
+                }
+
+                bool register_output_format(osmium::io::file_format format, create_output_type create_function) {
+                    if (! m_callbacks.insert(map_type::value_type(format, create_function)).second) {
+                        return false;
+                    }
+                    return true;
+                }
+
+                std::unique_ptr<osmium::io::detail::OutputFormat> create_output(const osmium::io::File& file, future_string_queue_type& output_queue) {
+                    auto it = m_callbacks.find(file.format());
+                    if (it != m_callbacks.end()) {
+                        return std::unique_ptr<osmium::io::detail::OutputFormat>((it->second)(file, output_queue));
+                    }
+
+                    throw unsupported_file_format_error(
+                                std::string("Can not open file '") +
+                                file.filename() +
+                                "' with type '" +
+                                as_string(file.format()) +
+                                "'. No support for writing this format in this program.");
+                }
+
+            }; // class OutputFormatFactory
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_OUTPUT_FORMAT_HPP
diff --git a/contrib/libosmium/osmium/io/detail/pbf.hpp b/contrib/libosmium/osmium/io/detail/pbf.hpp
new file mode 100644
index 0000000..4a32a63
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/pbf.hpp
@@ -0,0 +1,89 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_HPP
+#define OSMIUM_IO_DETAIL_PBF_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdint>
+#include <string>
+
+// needed for htonl and ntohl
+#ifndef _WIN32
+# include <netinet/in.h>
+#else
+# include <winsock2.h>
+#endif
+
+#include <osmium/io/error.hpp>
+#include <osmium/osm/location.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when there was a problem with parsing the PBF format of
+     * a file.
+     */
+    struct pbf_error : public io_error {
+
+        pbf_error(const std::string& what) :
+            io_error(std::string("PBF error: ") + what) {
+        }
+
+        pbf_error(const char* what) :
+            io_error(std::string("PBF error: ") + what) {
+        }
+
+    }; // struct pbf_error
+
+    namespace io {
+
+        namespace detail {
+
+            // the maximum size of a blob header in bytes
+            const int max_blob_header_size = 64 * 1024; // 64 kB
+
+            // the maximum size of an uncompressed blob in bytes
+            const uint64_t max_uncompressed_blob_size = 32 * 1024 * 1024; // 32 MB
+
+            // resolution for longitude/latitude used for conversion
+            // between representation as double and as int
+            const int64_t lonlat_resolution = 1000 * 1000 * 1000;
+
+            const int64_t resolution_convert = lonlat_resolution / osmium::Location::coordinate_precision;
+
+        }
+
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_HPP
diff --git a/contrib/libosmium/osmium/io/detail/pbf_decoder.hpp b/contrib/libosmium/osmium/io/detail/pbf_decoder.hpp
new file mode 100644
index 0000000..09e09bf
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/pbf_decoder.hpp
@@ -0,0 +1,777 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_DECODER_HPP
+#define OSMIUM_IO_DETAIL_PBF_DECODER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <protozero/pbf_message.hpp>
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
+#include <osmium/io/detail/protobuf_tags.hpp>
+#include <osmium/io/detail/zlib.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/util/delta.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            using ptr_len_type = std::pair<const char*, size_t>;
+            using osm_string_len_type = std::pair<const char*, osmium::string_size_type>;
+
+            class PBFPrimitiveBlockDecoder {
+
+                static constexpr size_t initial_buffer_size = 2 * 1024 * 1024;
+
+                ptr_len_type m_data;
+                std::vector<osm_string_len_type> m_stringtable;
+
+                int64_t m_lon_offset = 0;
+                int64_t m_lat_offset = 0;
+                int64_t m_date_factor = 1000;
+                int32_t m_granularity = 100;
+
+                osmium::osm_entity_bits::type m_read_types;
+
+                osmium::memory::Buffer m_buffer { initial_buffer_size };
+
+                void decode_stringtable(const ptr_len_type& data) {
+                    if (!m_stringtable.empty()) {
+                        throw osmium::pbf_error("more than one stringtable in pbf file");
+                    }
+
+                    protozero::pbf_message<OSMFormat::StringTable> pbf_string_table(data);
+                    while (pbf_string_table.next(OSMFormat::StringTable::repeated_bytes_s)) {
+                        auto str_len = pbf_string_table.get_data();
+                        if (str_len.second > osmium::max_osm_string_length) {
+                            throw osmium::pbf_error("overlong string in string table");
+                        }
+                        m_stringtable.emplace_back(str_len.first, osmium::string_size_type(str_len.second));
+                    }
+                }
+
+                void decode_primitive_block_metadata() {
+                    protozero::pbf_message<OSMFormat::PrimitiveBlock> pbf_primitive_block(m_data);
+                    while (pbf_primitive_block.next()) {
+                        switch (pbf_primitive_block.tag()) {
+                            case OSMFormat::PrimitiveBlock::required_StringTable_stringtable:
+                                decode_stringtable(pbf_primitive_block.get_data());
+                                break;
+                            case OSMFormat::PrimitiveBlock::optional_int32_granularity:
+                                m_granularity = pbf_primitive_block.get_int32();
+                                break;
+                            case OSMFormat::PrimitiveBlock::optional_int32_date_granularity:
+                                m_date_factor = pbf_primitive_block.get_int32();
+                                break;
+                            case OSMFormat::PrimitiveBlock::optional_int64_lat_offset:
+                                m_lat_offset = pbf_primitive_block.get_int64();
+                                break;
+                            case OSMFormat::PrimitiveBlock::optional_int64_lon_offset:
+                                m_lon_offset = pbf_primitive_block.get_int64();
+                                break;
+                            default:
+                                pbf_primitive_block.skip();
+                        }
+                    }
+                }
+
+                void decode_primitive_block_data() {
+                    protozero::pbf_message<OSMFormat::PrimitiveBlock> pbf_primitive_block(m_data);
+                    while (pbf_primitive_block.next(OSMFormat::PrimitiveBlock::repeated_PrimitiveGroup_primitivegroup)) {
+                        protozero::pbf_message<OSMFormat::PrimitiveGroup> pbf_primitive_group = pbf_primitive_block.get_message();
+                        while (pbf_primitive_group.next()) {
+                            switch (pbf_primitive_group.tag()) {
+                                case OSMFormat::PrimitiveGroup::repeated_Node_nodes:
+                                    if (m_read_types & osmium::osm_entity_bits::node) {
+                                        decode_node(pbf_primitive_group.get_data());
+                                    } else {
+                                        pbf_primitive_group.skip();
+                                    }
+                                    break;
+                                case OSMFormat::PrimitiveGroup::optional_DenseNodes_dense:
+                                    if (m_read_types & osmium::osm_entity_bits::node) {
+                                        decode_dense_nodes(pbf_primitive_group.get_data());
+                                    } else {
+                                        pbf_primitive_group.skip();
+                                    }
+                                    break;
+                                case OSMFormat::PrimitiveGroup::repeated_Way_ways:
+                                    if (m_read_types & osmium::osm_entity_bits::way) {
+                                        decode_way(pbf_primitive_group.get_data());
+                                    } else {
+                                        pbf_primitive_group.skip();
+                                    }
+                                    break;
+                                case OSMFormat::PrimitiveGroup::repeated_Relation_relations:
+                                    if (m_read_types & osmium::osm_entity_bits::relation) {
+                                        decode_relation(pbf_primitive_group.get_data());
+                                    } else {
+                                        pbf_primitive_group.skip();
+                                    }
+                                    break;
+                                default:
+                                    pbf_primitive_group.skip();
+                            }
+                        }
+                    }
+                }
+
+                osm_string_len_type decode_info(const ptr_len_type& data, osmium::OSMObject& object) {
+                    osm_string_len_type user = std::make_pair("", 0);
+
+                    protozero::pbf_message<OSMFormat::Info> pbf_info(data);
+                    while (pbf_info.next()) {
+                        switch (pbf_info.tag()) {
+                            case OSMFormat::Info::optional_int32_version:
+                                {
+                                    auto version = pbf_info.get_int32();
+                                    if (version < 0) {
+                                        throw osmium::pbf_error("object version must not be negative");
+                                    }
+                                    object.set_version(static_cast_with_assert<object_version_type>(version));
+                                }
+                                break;
+                            case OSMFormat::Info::optional_int64_timestamp:
+                                object.set_timestamp(pbf_info.get_int64() * m_date_factor / 1000);
+                                break;
+                            case OSMFormat::Info::optional_int64_changeset:
+                                {
+                                    auto changeset_id = pbf_info.get_int64();
+                                    if (changeset_id < 0) {
+                                        throw osmium::pbf_error("object changeset_id must not be negative");
+                                    }
+                                    object.set_changeset(static_cast_with_assert<changeset_id_type>(changeset_id));
+                                }
+                                break;
+                            case OSMFormat::Info::optional_int32_uid:
+                                object.set_uid_from_signed(pbf_info.get_int32());
+                                break;
+                            case OSMFormat::Info::optional_uint32_user_sid:
+                                user = m_stringtable.at(pbf_info.get_uint32());
+                                break;
+                            case OSMFormat::Info::optional_bool_visible:
+                                object.set_visible(pbf_info.get_bool());
+                                break;
+                            default:
+                                pbf_info.skip();
+                        }
+                    }
+
+                    return user;
+                }
+
+                using kv_type = std::pair<protozero::pbf_reader::const_uint32_iterator, protozero::pbf_reader::const_uint32_iterator>;
+
+                void build_tag_list(osmium::builder::Builder& builder, const kv_type& keys, const kv_type& vals) {
+                    if (keys.first != keys.second) {
+                        osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
+                        auto kit = keys.first;
+                        auto vit = vals.first;
+                        while (kit != keys.second) {
+                            if (vit == vals.second) {
+                                // this is against the spec, must have same number of elements
+                                throw osmium::pbf_error("PBF format error");
+                            }
+                            const auto& k = m_stringtable.at(*kit++);
+                            const auto& v = m_stringtable.at(*vit++);
+                            tl_builder.add_tag(k.first, k.second, v.first, v.second);
+                        }
+                    }
+                }
+
+                int32_t convert_pbf_coordinate(int64_t c) const {
+                    return int32_t((c * m_granularity + m_lon_offset) / resolution_convert);
+                }
+
+                void decode_node(const ptr_len_type& data) {
+                    osmium::builder::NodeBuilder builder(m_buffer);
+                    osmium::Node& node = builder.object();
+
+                    kv_type keys;
+                    kv_type vals;
+                    int64_t lon = std::numeric_limits<int64_t>::max();
+                    int64_t lat = std::numeric_limits<int64_t>::max();
+
+                    osm_string_len_type user = { "", 0 };
+
+                    protozero::pbf_message<OSMFormat::Node> pbf_node(data);
+                    while (pbf_node.next()) {
+                        switch (pbf_node.tag()) {
+                            case OSMFormat::Node::required_sint64_id:
+                                node.set_id(pbf_node.get_sint64());
+                                break;
+                            case OSMFormat::Node::packed_uint32_keys:
+                                keys = pbf_node.get_packed_uint32();
+                                break;
+                            case OSMFormat::Node::packed_uint32_vals:
+                                vals = pbf_node.get_packed_uint32();
+                                break;
+                            case OSMFormat::Node::optional_Info_info:
+                                user = decode_info(pbf_node.get_data(), builder.object());
+                                break;
+                            case OSMFormat::Node::required_sint64_lat:
+                                lat = pbf_node.get_sint64();
+                                break;
+                            case OSMFormat::Node::required_sint64_lon:
+                                lon = pbf_node.get_sint64();
+                                break;
+                            default:
+                                pbf_node.skip();
+                        }
+                    }
+
+                    if (node.visible()) {
+                        if (lon == std::numeric_limits<int64_t>::max() ||
+                            lat == std::numeric_limits<int64_t>::max()) {
+                            throw osmium::pbf_error("illegal coordinate format");
+                        }
+                        node.set_location(osmium::Location(
+                                convert_pbf_coordinate(lon),
+                                convert_pbf_coordinate(lat)
+                        ));
+                    }
+
+                    builder.add_user(user.first, user.second);
+
+                    build_tag_list(builder, keys, vals);
+
+                    m_buffer.commit();
+                }
+
+                void decode_way(const ptr_len_type& data) {
+                    osmium::builder::WayBuilder builder(m_buffer);
+
+                    kv_type keys;
+                    kv_type vals;
+                    std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> refs;
+
+                    osm_string_len_type user = { "", 0 };
+
+                    protozero::pbf_message<OSMFormat::Way> pbf_way(data);
+                    while (pbf_way.next()) {
+                        switch (pbf_way.tag()) {
+                            case OSMFormat::Way::required_int64_id:
+                                builder.object().set_id(pbf_way.get_int64());
+                                break;
+                            case OSMFormat::Way::packed_uint32_keys:
+                                keys = pbf_way.get_packed_uint32();
+                                break;
+                            case OSMFormat::Way::packed_uint32_vals:
+                                vals = pbf_way.get_packed_uint32();
+                                break;
+                            case OSMFormat::Way::optional_Info_info:
+                                user = decode_info(pbf_way.get_data(), builder.object());
+                                break;
+                            case OSMFormat::Way::packed_sint64_refs:
+                                refs = pbf_way.get_packed_sint64();
+                                break;
+                            default:
+                                pbf_way.skip();
+                        }
+                    }
+
+                    builder.add_user(user.first, user.second);
+
+                    if (refs.first != refs.second) {
+                        osmium::builder::WayNodeListBuilder wnl_builder(m_buffer, &builder);
+                        osmium::util::DeltaDecode<int64_t> ref;
+                        while (refs.first != refs.second) {
+                            wnl_builder.add_node_ref(ref.update(*refs.first++));
+                        }
+                    }
+
+                    build_tag_list(builder, keys, vals);
+
+                    m_buffer.commit();
+                }
+
+                void decode_relation(const ptr_len_type& data) {
+                    osmium::builder::RelationBuilder builder(m_buffer);
+
+                    kv_type keys;
+                    kv_type vals;
+                    std::pair<protozero::pbf_reader::const_int32_iterator,  protozero::pbf_reader::const_int32_iterator> roles;
+                    std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> refs;
+                    std::pair<protozero::pbf_reader::const_int32_iterator,  protozero::pbf_reader::const_int32_iterator> types;
+
+                    osm_string_len_type user = { "", 0 };
+
+                    protozero::pbf_message<OSMFormat::Relation> pbf_relation(data);
+                    while (pbf_relation.next()) {
+                        switch (pbf_relation.tag()) {
+                            case OSMFormat::Relation::required_int64_id:
+                                builder.object().set_id(pbf_relation.get_int64());
+                                break;
+                            case OSMFormat::Relation::packed_uint32_keys:
+                                keys = pbf_relation.get_packed_uint32();
+                                break;
+                            case OSMFormat::Relation::packed_uint32_vals:
+                                vals = pbf_relation.get_packed_uint32();
+                                break;
+                            case OSMFormat::Relation::optional_Info_info:
+                                user = decode_info(pbf_relation.get_data(), builder.object());
+                                break;
+                            case OSMFormat::Relation::packed_int32_roles_sid:
+                                roles = pbf_relation.get_packed_int32();
+                                break;
+                            case OSMFormat::Relation::packed_sint64_memids:
+                                refs = pbf_relation.get_packed_sint64();
+                                break;
+                            case OSMFormat::Relation::packed_MemberType_types:
+                                types = pbf_relation.get_packed_enum();
+                                break;
+                            default:
+                                pbf_relation.skip();
+                        }
+                    }
+
+                    builder.add_user(user.first, user.second);
+
+                    if (refs.first != refs.second) {
+                        osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
+                        osmium::util::DeltaDecode<int64_t> ref;
+                        while (roles.first != roles.second && refs.first != refs.second && types.first != types.second) {
+                            const auto& r = m_stringtable.at(*roles.first++);
+                            int type = *types.first++;
+                            if (type < 0 || type > 2) {
+                                throw osmium::pbf_error("unknown relation member type");
+                            }
+                            rml_builder.add_member(
+                                osmium::item_type(type + 1),
+                                ref.update(*refs.first++),
+                                r.first,
+                                r.second
+                            );
+                        }
+                    }
+
+                    build_tag_list(builder, keys, vals);
+
+                    m_buffer.commit();
+                }
+
+                void decode_dense_nodes(const ptr_len_type& data) {
+                    bool has_info     = false;
+                    bool has_visibles = false;
+
+                    std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> ids;
+                    std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> lats;
+                    std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> lons;
+
+                    std::pair<protozero::pbf_reader::const_int32_iterator,  protozero::pbf_reader::const_int32_iterator>  tags;
+
+                    std::pair<protozero::pbf_reader::const_int32_iterator,  protozero::pbf_reader::const_int32_iterator>  versions;
+                    std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> timestamps;
+                    std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> changesets;
+                    std::pair<protozero::pbf_reader::const_sint32_iterator, protozero::pbf_reader::const_sint32_iterator> uids;
+                    std::pair<protozero::pbf_reader::const_sint32_iterator, protozero::pbf_reader::const_sint32_iterator> user_sids;
+                    std::pair<protozero::pbf_reader::const_int32_iterator,  protozero::pbf_reader::const_int32_iterator>  visibles;
+
+                    protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes(data);
+                    while (pbf_dense_nodes.next()) {
+                        switch (pbf_dense_nodes.tag()) {
+                            case OSMFormat::DenseNodes::packed_sint64_id:
+                                ids = pbf_dense_nodes.get_packed_sint64();
+                                break;
+                            case OSMFormat::DenseNodes::optional_DenseInfo_denseinfo:
+                                {
+                                    has_info = true;
+                                    protozero::pbf_message<OSMFormat::DenseInfo> pbf_dense_info = pbf_dense_nodes.get_message();
+                                    while (pbf_dense_info.next()) {
+                                        switch (pbf_dense_info.tag()) {
+                                            case OSMFormat::DenseInfo::packed_int32_version:
+                                                versions = pbf_dense_info.get_packed_int32();
+                                                break;
+                                            case OSMFormat::DenseInfo::packed_sint64_timestamp:
+                                                timestamps = pbf_dense_info.get_packed_sint64();
+                                                break;
+                                            case OSMFormat::DenseInfo::packed_sint64_changeset:
+                                                changesets = pbf_dense_info.get_packed_sint64();
+                                                break;
+                                            case OSMFormat::DenseInfo::packed_sint32_uid:
+                                                uids = pbf_dense_info.get_packed_sint32();
+                                                break;
+                                            case OSMFormat::DenseInfo::packed_sint32_user_sid:
+                                                user_sids = pbf_dense_info.get_packed_sint32();
+                                                break;
+                                            case OSMFormat::DenseInfo::packed_bool_visible:
+                                                has_visibles = true;
+                                                visibles = pbf_dense_info.get_packed_bool();
+                                                break;
+                                            default:
+                                                pbf_dense_info.skip();
+                                        }
+                                    }
+                                }
+                                break;
+                            case OSMFormat::DenseNodes::packed_sint64_lat:
+                                lats = pbf_dense_nodes.get_packed_sint64();
+                                break;
+                            case OSMFormat::DenseNodes::packed_sint64_lon:
+                                lons = pbf_dense_nodes.get_packed_sint64();
+                                break;
+                            case OSMFormat::DenseNodes::packed_int32_keys_vals:
+                                tags = pbf_dense_nodes.get_packed_int32();
+                                break;
+                            default:
+                                pbf_dense_nodes.skip();
+                        }
+                    }
+
+                    osmium::util::DeltaDecode<int64_t> dense_id;
+                    osmium::util::DeltaDecode<int64_t> dense_latitude;
+                    osmium::util::DeltaDecode<int64_t> dense_longitude;
+                    osmium::util::DeltaDecode<int64_t> dense_uid;
+                    osmium::util::DeltaDecode<int64_t> dense_user_sid;
+                    osmium::util::DeltaDecode<int64_t> dense_changeset;
+                    osmium::util::DeltaDecode<int64_t> dense_timestamp;
+
+                    auto tag_it = tags.first;
+
+                    while (ids.first != ids.second) {
+                        if (lons.first == lons.second ||
+                            lats.first == lats.second) {
+                            // this is against the spec, must have same number of elements
+                            throw osmium::pbf_error("PBF format error");
+                        }
+
+                        bool visible = true;
+
+                        osmium::builder::NodeBuilder builder(m_buffer);
+                        osmium::Node& node = builder.object();
+
+                        node.set_id(dense_id.update(*ids.first++));
+
+                        if (has_info) {
+                            if (versions.first == versions.second ||
+                                changesets.first == changesets.second ||
+                                timestamps.first == timestamps.second ||
+                                uids.first == uids.second ||
+                                user_sids.first == user_sids.second) {
+                                // this is against the spec, must have same number of elements
+                                throw osmium::pbf_error("PBF format error");
+                            }
+
+                            auto version = *versions.first++;
+                            if (version < 0) {
+                                throw osmium::pbf_error("object version must not be negative");
+                            }
+                            node.set_version(static_cast<osmium::object_version_type>(version));
+
+                            auto changeset_id = dense_changeset.update(*changesets.first++);
+                            if (changeset_id < 0) {
+                                throw osmium::pbf_error("object changeset_id must not be negative");
+                            }
+                            node.set_changeset(static_cast<osmium::changeset_id_type>(changeset_id));
+
+                            node.set_timestamp(dense_timestamp.update(*timestamps.first++) * m_date_factor / 1000);
+                            node.set_uid_from_signed(static_cast<osmium::signed_user_id_type>(dense_uid.update(*uids.first++)));
+
+                            if (has_visibles) {
+                                if (visibles.first == visibles.second) {
+                                    // this is against the spec, must have same number of elements
+                                    throw osmium::pbf_error("PBF format error");
+                                }
+                                visible = (*visibles.first++) != 0;
+                            }
+                            node.set_visible(visible);
+
+                            const auto& u = m_stringtable.at(dense_user_sid.update(*user_sids.first++));
+                            builder.add_user(u.first, u.second);
+                        } else {
+                            builder.add_user("");
+                        }
+
+                        // even if the node isn't visible, there's still a record
+                        // of its lat/lon in the dense arrays.
+                        const auto lon = dense_longitude.update(*lons.first++);
+                        const auto lat = dense_latitude.update(*lats.first++);
+                        if (visible) {
+                            builder.object().set_location(osmium::Location(
+                                    convert_pbf_coordinate(lon),
+                                    convert_pbf_coordinate(lat)
+                            ));
+                        }
+
+                        if (tag_it != tags.second) {
+                            osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
+                            while (tag_it != tags.second && *tag_it != 0) {
+                                const auto& k = m_stringtable.at(*tag_it++);
+                                if (tag_it == tags.second) {
+                                    throw osmium::pbf_error("PBF format error"); // this is against the spec, keys/vals must come in pairs
+                                }
+                                const auto& v = m_stringtable.at(*tag_it++);
+                                tl_builder.add_tag(k.first, k.second, v.first, v.second);
+                            }
+
+                            if (tag_it != tags.second) {
+                                ++tag_it;
+                            }
+                        }
+
+                        m_buffer.commit();
+                    }
+
+                }
+
+            public:
+
+                PBFPrimitiveBlockDecoder(const ptr_len_type& data, osmium::osm_entity_bits::type read_types) :
+                    m_data(data),
+                    m_read_types(read_types) {
+                }
+
+                PBFPrimitiveBlockDecoder(const PBFPrimitiveBlockDecoder&) = delete;
+                PBFPrimitiveBlockDecoder& operator=(const PBFPrimitiveBlockDecoder&) = delete;
+
+                PBFPrimitiveBlockDecoder(PBFPrimitiveBlockDecoder&&) = delete;
+                PBFPrimitiveBlockDecoder& operator=(PBFPrimitiveBlockDecoder&&) = delete;
+
+                ~PBFPrimitiveBlockDecoder() noexcept = default;
+
+                osmium::memory::Buffer operator()() {
+                    try {
+                        decode_primitive_block_metadata();
+                        decode_primitive_block_data();
+                    } catch (std::out_of_range&) {
+                        throw osmium::pbf_error("string id out of range");
+                    }
+
+                    return std::move(m_buffer);
+                }
+
+            }; // class PBFPrimitiveBlockDecoder
+
+            inline ptr_len_type decode_blob(const std::string& blob_data, std::string& output) {
+                int32_t raw_size = 0;
+                std::pair<const char*, protozero::pbf_length_type> zlib_data = {nullptr, 0};
+
+                protozero::pbf_message<FileFormat::Blob> pbf_blob(blob_data);
+                while (pbf_blob.next()) {
+                    switch (pbf_blob.tag()) {
+                        case FileFormat::Blob::optional_bytes_raw:
+                            {
+                                auto data_len = pbf_blob.get_data();
+                                if (data_len.second > max_uncompressed_blob_size) {
+                                    throw osmium::pbf_error("illegal blob size");
+                                }
+                                return data_len;
+                            }
+                        case FileFormat::Blob::optional_int32_raw_size:
+                            raw_size = pbf_blob.get_int32();
+                            if (raw_size <= 0 || uint32_t(raw_size) > max_uncompressed_blob_size) {
+                                throw osmium::pbf_error("illegal blob size");
+                            }
+                            break;
+                        case FileFormat::Blob::optional_bytes_zlib_data:
+                            zlib_data = pbf_blob.get_data();
+                            break;
+                        case FileFormat::Blob::optional_bytes_lzma_data:
+                            throw osmium::pbf_error("lzma blobs not implemented");
+                        default:
+                            throw osmium::pbf_error("unknown compression");
+                    }
+                }
+
+                if (zlib_data.second != 0 && raw_size != 0) {
+                    return osmium::io::detail::zlib_uncompress_string(
+                        zlib_data.first,
+                        static_cast<unsigned long>(zlib_data.second),
+                        static_cast<unsigned long>(raw_size),
+                        output
+                    );
+                }
+
+                throw osmium::pbf_error("blob contains no data");
+            }
+
+            inline osmium::Box decode_header_bbox(const ptr_len_type& data) {
+                    int64_t left   = std::numeric_limits<int64_t>::max();
+                    int64_t right  = std::numeric_limits<int64_t>::max();
+                    int64_t top    = std::numeric_limits<int64_t>::max();
+                    int64_t bottom = std::numeric_limits<int64_t>::max();
+
+                    protozero::pbf_message<OSMFormat::HeaderBBox> pbf_header_bbox(data);
+                    while (pbf_header_bbox.next()) {
+                        switch (pbf_header_bbox.tag()) {
+                            case OSMFormat::HeaderBBox::required_sint64_left:
+                                left = pbf_header_bbox.get_sint64();
+                                break;
+                            case OSMFormat::HeaderBBox::required_sint64_right:
+                                right = pbf_header_bbox.get_sint64();
+                                break;
+                            case OSMFormat::HeaderBBox::required_sint64_top:
+                                top = pbf_header_bbox.get_sint64();
+                                break;
+                            case OSMFormat::HeaderBBox::required_sint64_bottom:
+                                bottom = pbf_header_bbox.get_sint64();
+                                break;
+                            default:
+                                pbf_header_bbox.skip();
+                        }
+                    }
+
+                    if (left   == std::numeric_limits<int64_t>::max() ||
+                        right  == std::numeric_limits<int64_t>::max() ||
+                        top    == std::numeric_limits<int64_t>::max() ||
+                        bottom == std::numeric_limits<int64_t>::max()) {
+                        throw osmium::pbf_error("invalid bbox");
+                    }
+
+                    osmium::Box box;
+                    box.extend(osmium::Location(left  / resolution_convert, bottom / resolution_convert));
+                    box.extend(osmium::Location(right / resolution_convert, top    / resolution_convert));
+
+                    return box;
+            }
+
+            inline osmium::io::Header decode_header_block(const ptr_len_type& data) {
+                osmium::io::Header header;
+                int i = 0;
+
+                protozero::pbf_message<OSMFormat::HeaderBlock> pbf_header_block(data);
+                while (pbf_header_block.next()) {
+                    switch (pbf_header_block.tag()) {
+                        case OSMFormat::HeaderBlock::optional_HeaderBBox_bbox:
+                            header.add_box(decode_header_bbox(pbf_header_block.get_data()));
+                            break;
+                        case OSMFormat::HeaderBlock::repeated_string_required_features:
+                            {
+                                auto feature = pbf_header_block.get_data();
+                                if (!strncmp("OsmSchema-V0.6", feature.first, feature.second)) {
+                                    // intentionally left blank
+                                } else if (!strncmp("DenseNodes", feature.first, feature.second)) {
+                                    header.set("pbf_dense_nodes", true);
+                                } else if (!strncmp("HistoricalInformation", feature.first, feature.second)) {
+                                    header.set_has_multiple_object_versions(true);
+                                } else {
+                                    std::string msg("required feature not supported: ");
+                                    msg.append(feature.first, feature.second);
+                                    throw osmium::pbf_error(msg);
+                                }
+                            }
+                            break;
+                        case OSMFormat::HeaderBlock::repeated_string_optional_features:
+                            header.set("pbf_optional_feature_" + std::to_string(i++), pbf_header_block.get_string());
+                            break;
+                        case OSMFormat::HeaderBlock::optional_string_writingprogram:
+                            header.set("generator", pbf_header_block.get_string());
+                            break;
+                        case OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp:
+                            {
+                                auto timestamp = osmium::Timestamp(pbf_header_block.get_int64()).to_iso();
+                                header.set("osmosis_replication_timestamp", timestamp);
+                                header.set("timestamp", timestamp);
+                            }
+                            break;
+                        case OSMFormat::HeaderBlock::optional_int64_osmosis_replication_sequence_number:
+                            header.set("osmosis_replication_sequence_number", std::to_string(pbf_header_block.get_int64()));
+                            break;
+                        case OSMFormat::HeaderBlock::optional_string_osmosis_replication_base_url:
+                            header.set("osmosis_replication_base_url", pbf_header_block.get_string());
+                            break;
+                        default:
+                            pbf_header_block.skip();
+                    }
+                }
+
+                return header;
+            }
+
+            /**
+             * Decode HeaderBlock.
+             *
+             * @param header_block_data Input data
+             * @returns Header object
+             * @throws osmium::pbf_error If there was a parsing error
+             */
+            inline osmium::io::Header decode_header(const std::string& header_block_data) {
+                std::string output;
+
+                return decode_header_block(decode_blob(header_block_data, output));
+            }
+
+            class PBFDataBlobDecoder {
+
+                std::shared_ptr<std::string> m_input_buffer;
+                osmium::osm_entity_bits::type m_read_types;
+
+            public:
+
+                PBFDataBlobDecoder(std::string&& input_buffer, osmium::osm_entity_bits::type read_types) :
+                    m_input_buffer(std::make_shared<std::string>(std::move(input_buffer))),
+                    m_read_types(read_types) {
+                }
+
+                PBFDataBlobDecoder(const PBFDataBlobDecoder&) = default;
+                PBFDataBlobDecoder& operator=(const PBFDataBlobDecoder&) = default;
+
+                PBFDataBlobDecoder(PBFDataBlobDecoder&&) = default;
+                PBFDataBlobDecoder& operator=(PBFDataBlobDecoder&&) = default;
+
+                ~PBFDataBlobDecoder() noexcept = default;
+
+                osmium::memory::Buffer operator()() {
+                    std::string output;
+                    PBFPrimitiveBlockDecoder decoder(decode_blob(*m_input_buffer, output), m_read_types);
+                    return decoder();
+                }
+
+            }; // class PBFDataBlobDecoder
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_DECODER_HPP
diff --git a/contrib/libosmium/osmium/io/detail/pbf_input_format.hpp b/contrib/libosmium/osmium/io/detail/pbf_input_format.hpp
new file mode 100644
index 0000000..4464fd7
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/pbf_input_format.hpp
@@ -0,0 +1,242 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_INPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_PBF_INPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <type_traits>
+
+#include <protozero/pbf_message.hpp>
+
+#include <osmium/io/detail/input_format.hpp>
+#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
+#include <osmium/io/detail/pbf_decoder.hpp>
+#include <osmium/io/detail/protobuf_tags.hpp>
+#include <osmium/io/error.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/thread/pool.hpp>
+#include <osmium/thread/util.hpp>
+#include <osmium/util/config.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            class PBFParser : public Parser {
+
+                std::string m_input_buffer;
+
+                /**
+                 * Read the given number of bytes from the input queue.
+                 *
+                 * @param size Number of bytes to read
+                 * @returns String with the data
+                 * @throws osmium::pbf_error If size bytes can't be read
+                 */
+                std::string read_from_input_queue(size_t size) {
+                    while (m_input_buffer.size() < size) {
+                        std::string new_data = get_input();
+                        if (input_done()) {
+                            throw osmium::pbf_error("truncated data (EOF encountered)");
+                        }
+                        m_input_buffer += new_data;
+                    }
+
+                    std::string output { m_input_buffer.substr(size) };
+                    m_input_buffer.resize(size);
+
+                    using std::swap;
+                    swap(output, m_input_buffer);
+
+                    return output;
+                }
+
+                /**
+                 * Read 4 bytes in network byte order from file. They contain
+                 * the length of the following BlobHeader.
+                 */
+                uint32_t read_blob_header_size_from_file() {
+                    uint32_t size_in_network_byte_order;
+
+                    try {
+                        const std::string input_data = read_from_input_queue(sizeof(size_in_network_byte_order));
+                        size_in_network_byte_order = *reinterpret_cast<const uint32_t*>(input_data.data());
+                    } catch (osmium::pbf_error&) {
+                        return 0; // EOF
+                    }
+
+                    const uint32_t size = ntohl(size_in_network_byte_order);
+                    if (size > static_cast<uint32_t>(max_blob_header_size)) {
+                        throw osmium::pbf_error("invalid BlobHeader size (> max_blob_header_size)");
+                    }
+
+                    return size;
+                }
+
+                /**
+                 * Decode the BlobHeader. Make sure it contains the expected
+                 * type. Return the size of the following Blob.
+                 */
+                size_t decode_blob_header(protozero::pbf_message<FileFormat::BlobHeader>&& pbf_blob_header, const char* expected_type) {
+                    std::pair<const char*, size_t> blob_header_type;
+                    size_t blob_header_datasize = 0;
+
+                    while (pbf_blob_header.next()) {
+                        switch (pbf_blob_header.tag()) {
+                            case FileFormat::BlobHeader::required_string_type:
+                                blob_header_type = pbf_blob_header.get_data();
+                                break;
+                            case FileFormat::BlobHeader::required_int32_datasize:
+                                blob_header_datasize = pbf_blob_header.get_int32();
+                                break;
+                            default:
+                                pbf_blob_header.skip();
+                        }
+                    }
+
+                    if (blob_header_datasize == 0) {
+                        throw osmium::pbf_error("PBF format error: BlobHeader.datasize missing or zero.");
+                    }
+
+                    if (strncmp(expected_type, blob_header_type.first, blob_header_type.second)) {
+                        throw osmium::pbf_error("blob does not have expected type (OSMHeader in first blob, OSMData in following blobs)");
+                    }
+
+                    return blob_header_datasize;
+                }
+
+                size_t check_type_and_get_blob_size(const char* expected_type) {
+                    assert(expected_type);
+
+                    const auto size = read_blob_header_size_from_file();
+                    if (size == 0) { // EOF
+                        return 0;
+                    }
+
+                    const std::string blob_header = read_from_input_queue(size);
+
+                    return decode_blob_header(protozero::pbf_message<FileFormat::BlobHeader>(blob_header), expected_type);
+                }
+
+                std::string read_from_input_queue_with_check(size_t size) {
+                    if (size > max_uncompressed_blob_size) {
+                        throw osmium::pbf_error(std::string("invalid blob size: " +
+                                                std::to_string(size)));
+                    }
+                    return read_from_input_queue(size);
+                }
+
+                // Parse the header in the PBF OSMHeader blob.
+                void parse_header_blob() {
+                    osmium::io::Header header;
+                    const auto size = check_type_and_get_blob_size("OSMHeader");
+                    header = decode_header(read_from_input_queue_with_check(size));
+                    set_header_value(header);
+                }
+
+                void parse_data_blobs() {
+                    while (const auto size = check_type_and_get_blob_size("OSMData")) {
+                        std::string input_buffer = read_from_input_queue_with_check(size);
+
+                        PBFDataBlobDecoder data_blob_parser{ std::move(input_buffer), read_types() };
+
+                        if (osmium::config::use_pool_threads_for_pbf_parsing()) {
+                            send_to_output_queue(osmium::thread::Pool::instance().submit(std::move(data_blob_parser)));
+                        } else {
+                            send_to_output_queue(data_blob_parser());
+                        }
+                    }
+                }
+
+            public:
+
+                PBFParser(future_string_queue_type& input_queue,
+                          future_buffer_queue_type& output_queue,
+                          std::promise<osmium::io::Header>& header_promise,
+                          osmium::osm_entity_bits::type read_types) :
+                    Parser(input_queue, output_queue, header_promise, read_types),
+                    m_input_buffer() {
+                }
+
+                ~PBFParser() noexcept = default;
+
+                void run() override final {
+                    osmium::thread::set_thread_name("_osmium_pbf_in");
+
+                    parse_header_blob();
+
+                    if (read_types() != osmium::osm_entity_bits::nothing) {
+                        parse_data_blobs();
+                    }
+                }
+
+            }; // class PBFParser
+
+            // we want the register_parser() function to run, setting
+            // the variable is only a side-effect, it will never be used
+            const bool registered_pbf_parser = ParserFactory::instance().register_parser(
+                file_format::pbf,
+                [](future_string_queue_type& input_queue,
+                    future_buffer_queue_type& output_queue,
+                    std::promise<osmium::io::Header>& header_promise,
+                    osmium::osm_entity_bits::type read_which_entities) {
+                    return std::unique_ptr<Parser>(new PBFParser(input_queue, output_queue, header_promise, read_which_entities));
+            });
+
+            // dummy function to silence the unused variable warning from above
+            inline bool get_registered_pbf_parser() noexcept {
+                return registered_pbf_parser;
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_INPUT_FORMAT_HPP
diff --git a/contrib/libosmium/osmium/io/detail/pbf_output_format.hpp b/contrib/libosmium/osmium/io/detail/pbf_output_format.hpp
new file mode 100644
index 0000000..97b143b
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/pbf_output_format.hpp
@@ -0,0 +1,643 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_OUTPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_PBF_OUTPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstdint>
+#include <cstdlib>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <time.h>
+#include <utility>
+
+// needed for older boost libraries
+#define BOOST_RESULT_OF_USE_DECLTYPE
+#include <boost/iterator/transform_iterator.hpp>
+
+#include <protozero/pbf_builder.hpp>
+
+#include <osmium/handler.hpp>
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
+#include <osmium/io/detail/protobuf_tags.hpp>
+#include <osmium/io/detail/string_table.hpp>
+#include <osmium/io/detail/zlib.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/thread/pool.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/util/delta.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            struct pbf_output_options {
+
+                /// Should nodes be encoded in DenseNodes?
+                bool use_dense_nodes;
+
+                /**
+                 * Should the PBF blobs contain zlib compressed data?
+                 *
+                 * The zlib compression is optional, it's possible to store the
+                 * blobs in raw format. Disabling the compression can improve
+                 * the writing speed a little but the output will be 2x to 3x
+                 * bigger.
+                 */
+                bool use_compression;
+
+                /// Should metadata of objects be written?
+                bool add_metadata;
+
+                /// Add the "HistoricalInformation" header flag.
+                bool add_historical_information_flag;
+
+                /// Should the visible flag be added to all OSM objects?
+                bool add_visible_flag;
+
+            };
+
+            /**
+             * Maximum number of items in a primitive block.
+             *
+             * The uncompressed length of a Blob *should* be less
+             * than 16 megabytes and *must* be less than 32 megabytes.
+             *
+             * A block may contain any number of entities, as long as
+             * the size limits for the surrounding blob are obeyed.
+             * However, for simplicity, the current Osmosis (0.38)
+             * as well as Osmium implementation always
+             * uses at most 8k entities in a block.
+             */
+            constexpr int32_t max_entities_per_block = 8000;
+
+            constexpr int location_granularity = 100;
+
+            /**
+             * convert a double lat or lon value to an int, respecting the granularity
+             */
+            inline int64_t lonlat2int(double lonlat) {
+                return static_cast<int64_t>(std::round(lonlat * lonlat_resolution / location_granularity));
+            }
+
+            enum class pbf_blob_type {
+                header = 0,
+                data = 1
+            };
+
+            class SerializeBlob {
+
+                std::string m_msg;
+
+                pbf_blob_type m_blob_type;
+
+                bool m_use_compression;
+
+            public:
+
+                /**
+                 * Initialize a blob serializer.
+                 *
+                 * @param msg Protobuf-message containing the blob data
+                 * @param type Type of blob.
+                 * @param use_compression Should the output be compressed using
+                 *        zlib?
+                 */
+                SerializeBlob(std::string&& msg, pbf_blob_type type, bool use_compression) :
+                    m_msg(std::move(msg)),
+                    m_blob_type(type),
+                    m_use_compression(use_compression) {
+                }
+
+                /**
+                 * Serialize a protobuf message into a Blob, optionally apply
+                 * compression and return it together with a BlobHeader ready
+                 * to be written to a file.
+                 */
+                std::string operator()() {
+                    assert(m_msg.size() <= max_uncompressed_blob_size);
+
+                    std::string blob_data;
+                    protozero::pbf_builder<FileFormat::Blob> pbf_blob(blob_data);
+
+                    if (m_use_compression) {
+                        pbf_blob.add_int32(FileFormat::Blob::optional_int32_raw_size, int32_t(m_msg.size()));
+                        pbf_blob.add_bytes(FileFormat::Blob::optional_bytes_zlib_data, osmium::io::detail::zlib_compress(m_msg));
+                    } else {
+                        pbf_blob.add_bytes(FileFormat::Blob::optional_bytes_raw, m_msg);
+                    }
+
+                    std::string blob_header_data;
+                    protozero::pbf_builder<FileFormat::BlobHeader> pbf_blob_header(blob_header_data);
+
+                    pbf_blob_header.add_string(FileFormat::BlobHeader::required_string_type, m_blob_type == pbf_blob_type::data ? "OSMData" : "OSMHeader");
+                    pbf_blob_header.add_int32(FileFormat::BlobHeader::required_int32_datasize, static_cast_with_assert<int32_t>(blob_data.size()));
+
+                    uint32_t sz = htonl(static_cast_with_assert<uint32_t>(blob_header_data.size()));
+
+                    // write to output: the 4-byte BlobHeader-Size followed by the BlobHeader followed by the Blob
+                    std::string output;
+                    output.reserve(sizeof(sz) + blob_header_data.size() + blob_data.size());
+                    output.append(reinterpret_cast<const char*>(&sz), sizeof(sz));
+                    output.append(blob_header_data);
+                    output.append(blob_data);
+
+                    return output;
+                }
+
+            }; // class SerializeBlob
+
+            /**
+             * Contains the code to pack any number of nodes into a DenseNode
+             * structure.
+             *
+             * Because this needs to allocate a lot of memory on the heap,
+             * only one object of this class will be created and then re-used
+             * after calling clear() on it.
+             */
+            class DenseNodes {
+
+                StringTable& m_stringtable;
+
+                std::vector<int64_t> m_ids;
+
+                std::vector<int32_t> m_versions;
+                std::vector<int64_t> m_timestamps;
+                std::vector<int64_t> m_changesets;
+                std::vector<int32_t> m_uids;
+                std::vector<int32_t> m_user_sids;
+                std::vector<bool> m_visibles;
+
+                std::vector<int64_t> m_lats;
+                std::vector<int64_t> m_lons;
+                std::vector<int32_t> m_tags;
+
+                osmium::util::DeltaEncode<object_id_type, int64_t> m_delta_id;
+
+                osmium::util::DeltaEncode<time_t, int64_t> m_delta_timestamp;
+                osmium::util::DeltaEncode<changeset_id_type, int64_t> m_delta_changeset;
+                osmium::util::DeltaEncode<user_id_type, int32_t> m_delta_uid;
+                osmium::util::DeltaEncode<uint32_t, int32_t> m_delta_user_sid;
+
+                osmium::util::DeltaEncode<int64_t, int64_t> m_delta_lat;
+                osmium::util::DeltaEncode<int64_t, int64_t> m_delta_lon;
+
+                const pbf_output_options& m_options;
+
+            public:
+
+                DenseNodes(StringTable& stringtable, const pbf_output_options& options) :
+                    m_stringtable(stringtable),
+                    m_options(options) {
+                }
+
+                /// Clear object for re-use. Keep the allocated memory.
+                void clear() {
+                    m_ids.clear();
+
+                    m_versions.clear();
+                    m_timestamps.clear();
+                    m_changesets.clear();
+                    m_uids.clear();
+                    m_user_sids.clear();
+                    m_visibles.clear();
+
+                    m_lats.clear();
+                    m_lons.clear();
+                    m_tags.clear();
+
+                    m_delta_id.clear();
+
+                    m_delta_timestamp.clear();
+                    m_delta_changeset.clear();
+                    m_delta_uid.clear();
+                    m_delta_user_sid.clear();
+
+                    m_delta_lat.clear();
+                    m_delta_lon.clear();
+                }
+
+                size_t size() const {
+                    return m_ids.size() * 3 * sizeof(int64_t);
+                }
+
+                void add_node(const osmium::Node& node) {
+                    m_ids.push_back(m_delta_id.update(node.id()));
+
+                    if (m_options.add_metadata) {
+                        m_versions.push_back(static_cast_with_assert<int32_t>(node.version()));
+                        m_timestamps.push_back(m_delta_timestamp.update(node.timestamp()));
+                        m_changesets.push_back(m_delta_changeset.update(node.changeset()));
+                        m_uids.push_back(m_delta_uid.update(node.uid()));
+                        m_user_sids.push_back(m_delta_user_sid.update(m_stringtable.add(node.user())));
+                        if (m_options.add_visible_flag) {
+                            m_visibles.push_back(node.visible());
+                        }
+                    }
+
+                    m_lats.push_back(m_delta_lat.update(lonlat2int(node.location().lat_without_check())));
+                    m_lons.push_back(m_delta_lon.update(lonlat2int(node.location().lon_without_check())));
+
+                    for (const auto& tag : node.tags()) {
+                        m_tags.push_back(static_cast_with_assert<int32_t>(m_stringtable.add(tag.key())));
+                        m_tags.push_back(static_cast_with_assert<int32_t>(m_stringtable.add(tag.value())));
+                    }
+                    m_tags.push_back(0);
+                }
+
+                std::string serialize() const {
+                    std::string data;
+                    protozero::pbf_builder<OSMFormat::DenseNodes> pbf_dense_nodes(data);
+
+                    pbf_dense_nodes.add_packed_sint64(OSMFormat::DenseNodes::packed_sint64_id, m_ids.cbegin(), m_ids.cend());
+
+                    if (m_options.add_metadata) {
+                        protozero::pbf_builder<OSMFormat::DenseInfo> pbf_dense_info(pbf_dense_nodes, OSMFormat::DenseNodes::optional_DenseInfo_denseinfo);
+                        pbf_dense_info.add_packed_int32(OSMFormat::DenseInfo::packed_int32_version, m_versions.cbegin(), m_versions.cend());
+                        pbf_dense_info.add_packed_sint64(OSMFormat::DenseInfo::packed_sint64_timestamp, m_timestamps.cbegin(), m_timestamps.cend());
+                        pbf_dense_info.add_packed_sint64(OSMFormat::DenseInfo::packed_sint64_changeset, m_changesets.cbegin(), m_changesets.cend());
+                        pbf_dense_info.add_packed_sint32(OSMFormat::DenseInfo::packed_sint32_uid, m_uids.cbegin(), m_uids.cend());
+                        pbf_dense_info.add_packed_sint32(OSMFormat::DenseInfo::packed_sint32_user_sid, m_user_sids.cbegin(), m_user_sids.cend());
+
+                        if (m_options.add_visible_flag) {
+                            pbf_dense_info.add_packed_bool(OSMFormat::DenseInfo::packed_bool_visible, m_visibles.cbegin(), m_visibles.cend());
+                        }
+                    }
+
+                    pbf_dense_nodes.add_packed_sint64(OSMFormat::DenseNodes::packed_sint64_lat, m_lats.cbegin(), m_lats.cend());
+                    pbf_dense_nodes.add_packed_sint64(OSMFormat::DenseNodes::packed_sint64_lon, m_lons.cbegin(), m_lons.cend());
+
+                    pbf_dense_nodes.add_packed_int32(OSMFormat::DenseNodes::packed_int32_keys_vals, m_tags.cbegin(), m_tags.cend());
+
+                    return data;
+                }
+
+            }; // class DenseNodes
+
+            class PrimitiveBlock {
+
+                std::string m_pbf_primitive_group_data;
+                protozero::pbf_builder<OSMFormat::PrimitiveGroup> m_pbf_primitive_group;
+                StringTable m_stringtable;
+                DenseNodes m_dense_nodes;
+                OSMFormat::PrimitiveGroup m_type;
+                int m_count;
+
+            public:
+
+                PrimitiveBlock(const pbf_output_options& options) :
+                    m_pbf_primitive_group_data(),
+                    m_pbf_primitive_group(m_pbf_primitive_group_data),
+                    m_stringtable(),
+                    m_dense_nodes(m_stringtable, options),
+                    m_type(OSMFormat::PrimitiveGroup::unknown),
+                    m_count(0) {
+                }
+
+                const std::string& group_data() {
+                    if (type() == OSMFormat::PrimitiveGroup::optional_DenseNodes_dense) {
+                        m_pbf_primitive_group.add_message(OSMFormat::PrimitiveGroup::optional_DenseNodes_dense, m_dense_nodes.serialize());
+                    }
+                    return m_pbf_primitive_group_data;
+                }
+
+                void reset(OSMFormat::PrimitiveGroup type) {
+                    m_pbf_primitive_group_data.clear();
+                    m_stringtable.clear();
+                    m_dense_nodes.clear();
+                    m_type = type;
+                    m_count = 0;
+                }
+
+                void write_stringtable(protozero::pbf_builder<OSMFormat::StringTable>& pbf_string_table) {
+                    for (const char* s : m_stringtable) {
+                        pbf_string_table.add_bytes(OSMFormat::StringTable::repeated_bytes_s, s);
+                    }
+                }
+
+                protozero::pbf_builder<OSMFormat::PrimitiveGroup>& group() {
+                    ++m_count;
+                    return m_pbf_primitive_group;
+                }
+
+                void add_dense_node(const osmium::Node& node) {
+                    m_dense_nodes.add_node(node);
+                    ++m_count;
+                }
+
+                uint32_t store_in_stringtable(const char* s) {
+                    return m_stringtable.add(s);
+                }
+
+                int count() const {
+                    return m_count;
+                }
+
+                OSMFormat::PrimitiveGroup type() const {
+                    return m_type;
+                }
+
+                size_t size() const {
+                    return m_pbf_primitive_group_data.size() + m_stringtable.size() + m_dense_nodes.size();
+                }
+
+                /**
+                 * The output buffer (block) will be filled to about
+                 * 95% and then written to disk. This leaves more than
+                 * enough space for the string table (which typically
+                 * needs about 0.1 to 0.3% of the block size).
+                 */
+                constexpr static size_t max_used_blob_size = max_uncompressed_blob_size * 95 / 100;
+
+                bool can_add(OSMFormat::PrimitiveGroup type) const {
+                    if (type != m_type) {
+                        return false;
+                    }
+                    if (count() >= max_entities_per_block) {
+                        return false;
+                    }
+                    return size() < max_used_blob_size;
+                }
+
+            }; // class PrimitiveBlock
+
+            class PBFOutputFormat : public osmium::io::detail::OutputFormat, public osmium::handler::Handler {
+
+                pbf_output_options m_options;
+
+                PrimitiveBlock m_primitive_block;
+
+                void store_primitive_block() {
+                    if (m_primitive_block.count() == 0) {
+                        return;
+                    }
+
+                    std::string primitive_block_data;
+                    protozero::pbf_builder<OSMFormat::PrimitiveBlock> primitive_block(primitive_block_data);
+
+                    {
+                        protozero::pbf_builder<OSMFormat::StringTable> pbf_string_table(primitive_block, OSMFormat::PrimitiveBlock::required_StringTable_stringtable);
+                        m_primitive_block.write_stringtable(pbf_string_table);
+                    }
+
+                    primitive_block.add_message(OSMFormat::PrimitiveBlock::repeated_PrimitiveGroup_primitivegroup, m_primitive_block.group_data());
+
+                    m_output_queue.push(osmium::thread::Pool::instance().submit(
+                        SerializeBlob{std::move(primitive_block_data),
+                                      pbf_blob_type::data,
+                                      m_options.use_compression}
+                    ));
+                }
+
+                template <typename T>
+                void add_meta(const osmium::OSMObject& object, T& pbf_object) {
+                    const osmium::TagList& tags = object.tags();
+
+                    auto map_tag_key = [this](const osmium::Tag& tag) -> uint32_t {
+                        return m_primitive_block.store_in_stringtable(tag.key());
+                    };
+                    auto map_tag_value = [this](const osmium::Tag& tag) -> uint32_t {
+                        return m_primitive_block.store_in_stringtable(tag.value());
+                    };
+
+                    pbf_object.add_packed_uint32(T::enum_type::packed_uint32_keys,
+                        boost::make_transform_iterator(tags.begin(), map_tag_key),
+                        boost::make_transform_iterator(tags.end(), map_tag_key));
+
+                    pbf_object.add_packed_uint32(T::enum_type::packed_uint32_vals,
+                        boost::make_transform_iterator(tags.begin(), map_tag_value),
+                        boost::make_transform_iterator(tags.end(), map_tag_value));
+
+                    if (m_options.add_metadata) {
+                        protozero::pbf_builder<OSMFormat::Info> pbf_info(pbf_object, T::enum_type::optional_Info_info);
+
+                        pbf_info.add_int32(OSMFormat::Info::optional_int32_version, static_cast_with_assert<int32_t>(object.version()));
+                        pbf_info.add_int64(OSMFormat::Info::optional_int64_timestamp, object.timestamp());
+                        pbf_info.add_int64(OSMFormat::Info::optional_int64_changeset, object.changeset());
+                        pbf_info.add_int32(OSMFormat::Info::optional_int32_uid, static_cast_with_assert<int32_t>(object.uid()));
+                        pbf_info.add_uint32(OSMFormat::Info::optional_uint32_user_sid, m_primitive_block.store_in_stringtable(object.user()));
+                        if (m_options.add_visible_flag) {
+                            pbf_info.add_bool(OSMFormat::Info::optional_bool_visible, object.visible());
+                        }
+                    }
+                }
+
+                void switch_primitive_block_type(OSMFormat::PrimitiveGroup type) {
+                    if (!m_primitive_block.can_add(type)) {
+                        store_primitive_block();
+                        m_primitive_block.reset(type);
+                    }
+                }
+
+            public:
+
+                PBFOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
+                    OutputFormat(output_queue),
+                    m_options(),
+                    m_primitive_block(m_options) {
+                    m_options.use_dense_nodes = file.is_not_false("pbf_dense_nodes");
+                    m_options.use_compression = file.get("pbf_compression") != "none" && file.is_not_false("pbf_compression");
+                    m_options.add_metadata = file.is_not_false("pbf_add_metadata") && file.is_not_false("add_metadata");
+                    m_options.add_historical_information_flag = file.has_multiple_object_versions();
+                    m_options.add_visible_flag = file.has_multiple_object_versions();
+                }
+
+                PBFOutputFormat(const PBFOutputFormat&) = delete;
+                PBFOutputFormat& operator=(const PBFOutputFormat&) = delete;
+
+                ~PBFOutputFormat() noexcept = default;
+
+                void write_header(const osmium::io::Header& header) override final {
+                    std::string data;
+                    protozero::pbf_builder<OSMFormat::HeaderBlock> pbf_header_block(data);
+
+                    if (!header.boxes().empty()) {
+                        protozero::pbf_builder<OSMFormat::HeaderBBox> pbf_header_bbox(pbf_header_block, OSMFormat::HeaderBlock::optional_HeaderBBox_bbox);
+
+                        osmium::Box box = header.joined_boxes();
+                        pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_left,   int64_t(box.bottom_left().lon() * lonlat_resolution));
+                        pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_right,  int64_t(box.top_right().lon()   * lonlat_resolution));
+                        pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_top,    int64_t(box.top_right().lat()   * lonlat_resolution));
+                        pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_bottom, int64_t(box.bottom_left().lat() * lonlat_resolution));
+                    }
+
+                    pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_required_features, "OsmSchema-V0.6");
+
+                    if (m_options.use_dense_nodes) {
+                        pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_required_features, "DenseNodes");
+                    }
+
+                    if (m_options.add_historical_information_flag) {
+                        pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_required_features, "HistoricalInformation");
+                    }
+
+                    pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_writingprogram, header.get("generator"));
+
+                    std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp");
+                    if (!osmosis_replication_timestamp.empty()) {
+                        osmium::Timestamp ts(osmosis_replication_timestamp.c_str());
+                        pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp, ts);
+                    }
+
+                    std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number");
+                    if (!osmosis_replication_sequence_number.empty()) {
+                        pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_sequence_number, std::atoll(osmosis_replication_sequence_number.c_str()));
+                    }
+
+                    std::string osmosis_replication_base_url = header.get("osmosis_replication_base_url");
+                    if (!osmosis_replication_base_url.empty()) {
+                        pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_osmosis_replication_base_url, osmosis_replication_base_url);
+                    }
+
+                    m_output_queue.push(osmium::thread::Pool::instance().submit(
+                        SerializeBlob{std::move(data),
+                                      pbf_blob_type::header,
+                                      m_options.use_compression}
+                        ));
+                }
+
+                void write_buffer(osmium::memory::Buffer&& buffer) override final {
+                    osmium::apply(buffer.cbegin(), buffer.cend(), *this);
+                }
+
+                void write_end() override final {
+                    store_primitive_block();
+                }
+
+                void node(const osmium::Node& node) {
+                    if (m_options.use_dense_nodes) {
+                        switch_primitive_block_type(OSMFormat::PrimitiveGroup::optional_DenseNodes_dense);
+                        m_primitive_block.add_dense_node(node);
+                        return;
+                    }
+
+                    switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Node_nodes);
+                    protozero::pbf_builder<OSMFormat::Node> pbf_node{ m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Node_nodes };
+
+                    pbf_node.add_sint64(OSMFormat::Node::required_sint64_id, node.id());
+                    add_meta(node, pbf_node);
+
+                    pbf_node.add_sint64(OSMFormat::Node::required_sint64_lat, lonlat2int(node.location().lat_without_check()));
+                    pbf_node.add_sint64(OSMFormat::Node::required_sint64_lon, lonlat2int(node.location().lon_without_check()));
+                }
+
+                void way(const osmium::Way& way) {
+                    switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Way_ways);
+                    protozero::pbf_builder<OSMFormat::Way> pbf_way{ m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Way_ways };
+
+                    pbf_way.add_int64(OSMFormat::Way::required_int64_id, way.id());
+                    add_meta(way, pbf_way);
+
+                    static auto map_node_ref = [](osmium::NodeRefList::const_iterator node_ref) noexcept -> osmium::object_id_type {
+                        return node_ref->ref();
+                    };
+                    typedef osmium::util::DeltaEncodeIterator<osmium::NodeRefList::const_iterator, decltype(map_node_ref), osmium::object_id_type> it_type;
+
+                    const auto& nodes = way.nodes();
+                    it_type first { nodes.cbegin(), nodes.cend(), map_node_ref };
+                    it_type last { nodes.cend(), nodes.cend(), map_node_ref };
+                    pbf_way.add_packed_sint64(OSMFormat::Way::packed_sint64_refs, first, last);
+                }
+
+                void relation(const osmium::Relation& relation) {
+                    switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Relation_relations);
+                    protozero::pbf_builder<OSMFormat::Relation> pbf_relation { m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Relation_relations };
+
+                    pbf_relation.add_int64(OSMFormat::Relation::required_int64_id, relation.id());
+                    add_meta(relation, pbf_relation);
+
+                    auto map_member_role = [this](const osmium::RelationMember& member) -> uint32_t {
+                        return m_primitive_block.store_in_stringtable(member.role());
+                    };
+                    pbf_relation.add_packed_int32(OSMFormat::Relation::packed_int32_roles_sid,
+                        boost::make_transform_iterator(relation.members().begin(), map_member_role),
+                        boost::make_transform_iterator(relation.members().end(), map_member_role));
+
+                    static auto map_member_ref = [](osmium::RelationMemberList::const_iterator member) noexcept -> osmium::object_id_type {
+                        return member->ref();
+                    };
+                    typedef osmium::util::DeltaEncodeIterator<osmium::RelationMemberList::const_iterator, decltype(map_member_ref), osmium::object_id_type> it_type;
+                    const auto& members = relation.members();
+                    it_type first { members.cbegin(), members.cend(), map_member_ref };
+                    it_type last { members.cend(), members.cend(), map_member_ref };
+                    pbf_relation.add_packed_sint64(OSMFormat::Relation::packed_sint64_memids, first, last);
+
+                    static auto map_member_type = [](const osmium::RelationMember& member) noexcept -> int32_t {
+                        return int32_t(osmium::item_type_to_nwr_index(member.type()));
+                    };
+                    pbf_relation.add_packed_int32(OSMFormat::Relation::packed_MemberType_types,
+                        boost::make_transform_iterator(relation.members().begin(), map_member_type),
+                        boost::make_transform_iterator(relation.members().end(), map_member_type));
+                }
+
+            }; // class PBFOutputFormat
+
+            // we want the register_output_format() function to run, setting
+            // the variable is only a side-effect, it will never be used
+            const bool registered_pbf_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::pbf,
+                [](const osmium::io::File& file, future_string_queue_type& output_queue) {
+                    return new osmium::io::detail::PBFOutputFormat(file, output_queue);
+            });
+
+            // dummy function to silence the unused variable warning from above
+            inline bool get_registered_pbf_output() noexcept {
+                return registered_pbf_output;
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_OUTPUT_FORMAT_HPP
diff --git a/contrib/libosmium/osmium/io/detail/protobuf_tags.hpp b/contrib/libosmium/osmium/io/detail/protobuf_tags.hpp
new file mode 100644
index 0000000..3f23087
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/protobuf_tags.hpp
@@ -0,0 +1,170 @@
+#ifndef OSMIUM_IO_DETAIL_PROTOBUF_TAGS_HPP
+#define OSMIUM_IO_DETAIL_PROTOBUF_TAGS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <protozero/pbf_types.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            // directly translated from
+            // https://github.com/scrosby/OSM-binary/blob/master/src/fileformat.proto
+
+            namespace FileFormat {
+
+                enum class Blob : protozero::pbf_tag_type {
+                    optional_bytes_raw       = 1,
+                    optional_int32_raw_size  = 2,
+                    optional_bytes_zlib_data = 3,
+                    optional_bytes_lzma_data = 4
+                };
+
+                enum class BlobHeader : protozero::pbf_tag_type {
+                    required_string_type     = 1,
+                    optional_bytes_indexdata = 2,
+                    required_int32_datasize  = 3
+                };
+
+            } // namespace FileFormat
+
+            // directly translated from
+            // https://github.com/scrosby/OSM-binary/blob/master/src/osmformat.proto
+
+            namespace OSMFormat {
+
+                enum class HeaderBlock : protozero::pbf_tag_type {
+                    optional_HeaderBBox_bbox          =  1,
+                    repeated_string_required_features =  4,
+                    repeated_string_optional_features =  5,
+                    optional_string_writingprogram    = 16,
+                    optional_string_source            = 17,
+                    optional_int64_osmosis_replication_timestamp       = 32,
+                    optional_int64_osmosis_replication_sequence_number = 33,
+                    optional_string_osmosis_replication_base_url       = 34
+                };
+
+                enum class HeaderBBox : protozero::pbf_tag_type {
+                    required_sint64_left   = 1,
+                    required_sint64_right  = 2,
+                    required_sint64_top    = 3,
+                    required_sint64_bottom = 4
+                };
+
+                enum class PrimitiveBlock : protozero::pbf_tag_type {
+                    required_StringTable_stringtable       =  1,
+                    repeated_PrimitiveGroup_primitivegroup =  2,
+                    optional_int32_granularity             = 17,
+                    optional_int32_date_granularity        = 18,
+                    optional_int64_lat_offset              = 19,
+                    optional_int64_lon_offset              = 20
+                };
+
+                enum class PrimitiveGroup : protozero::pbf_tag_type {
+                    unknown                       = 0,
+                    repeated_Node_nodes           = 1,
+                    optional_DenseNodes_dense     = 2,
+                    repeated_Way_ways             = 3,
+                    repeated_Relation_relations   = 4,
+                    repeated_ChangeSet_changesets = 5
+                };
+
+                enum class StringTable : protozero::pbf_tag_type {
+                    repeated_bytes_s = 1
+                };
+
+                enum class Info : protozero::pbf_tag_type {
+                    optional_int32_version   = 1,
+                    optional_int64_timestamp = 2,
+                    optional_int64_changeset = 3,
+                    optional_int32_uid       = 4,
+                    optional_uint32_user_sid = 5,
+                    optional_bool_visible    = 6
+                };
+
+                enum class DenseInfo : protozero::pbf_tag_type {
+                    packed_int32_version    = 1,
+                    packed_sint64_timestamp = 2,
+                    packed_sint64_changeset = 3,
+                    packed_sint32_uid       = 4,
+                    packed_sint32_user_sid  = 5,
+                    packed_bool_visible     = 6
+                };
+
+                enum class Node : protozero::pbf_tag_type {
+                    required_sint64_id  = 1,
+                    packed_uint32_keys  = 2,
+                    packed_uint32_vals  = 3,
+                    optional_Info_info  = 4,
+                    required_sint64_lat = 8,
+                    required_sint64_lon = 9
+                };
+
+                enum class DenseNodes : protozero::pbf_tag_type {
+                    packed_sint64_id             =  1,
+                    optional_DenseInfo_denseinfo =  5,
+                    packed_sint64_lat            =  8,
+                    packed_sint64_lon            =  9,
+                    packed_int32_keys_vals       = 10
+                };
+
+                enum class Way : protozero::pbf_tag_type {
+                    required_int64_id  = 1,
+                    packed_uint32_keys = 2,
+                    packed_uint32_vals = 3,
+                    optional_Info_info = 4,
+                    packed_sint64_refs = 8
+                };
+
+                enum class Relation : protozero::pbf_tag_type {
+                    required_int64_id       =  1,
+                    packed_uint32_keys      =  2,
+                    packed_uint32_vals      =  3,
+                    optional_Info_info      =  4,
+                    packed_int32_roles_sid  =  8,
+                    packed_sint64_memids    =  9,
+                    packed_MemberType_types = 10
+                };
+
+            } // namespace OSMFormat
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif //  OSMIUM_IO_DETAIL_PROTOBUF_TAGS_HPP
diff --git a/contrib/libosmium/osmium/io/detail/queue_util.hpp b/contrib/libosmium/osmium/io/detail/queue_util.hpp
new file mode 100644
index 0000000..d410df1
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/queue_util.hpp
@@ -0,0 +1,157 @@
+#ifndef OSMIUM_IO_DETAIL_QUEUE_UTIL_HPP
+#define OSMIUM_IO_DETAIL_QUEUE_UTIL_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <exception>
+#include <future>
+#include <string>
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/thread/queue.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            /**
+             * This type of queue contains buffers with OSM data in them.
+             * The "end of file" is marked by an invalid Buffer.
+             * The buffers are wrapped in a std::future so that they can also
+             * transport exceptions. The future also helps with keeping the
+             * data in order.
+             */
+            using future_buffer_queue_type = osmium::thread::Queue<std::future<osmium::memory::Buffer>>;
+
+            /**
+             * This type of queue contains OSM file data in the form it is
+             * stored on disk, ie encoded as XML, PBF, etc.
+             * The "end of file" is marked by an empty string.
+             */
+            using string_queue_type = osmium::thread::Queue<std::string>;
+
+            /**
+             * This type of queue contains OSM file data in the form it is
+             * stored on disk, ie encoded as XML, PBF, etc.
+             * The "end of file" is marked by an empty string.
+             * The strings are wrapped in a std::future so that they can also
+             * transport exceptions. The future also helps with keeping the
+             * data in order.
+             */
+            using future_string_queue_type = osmium::thread::Queue<std::future<std::string>>;
+
+            template <typename T>
+            inline void add_to_queue(osmium::thread::Queue<std::future<T>>& queue, T&& data) {
+                std::promise<T> promise;
+                queue.push(promise.get_future());
+                promise.set_value(std::forward<T>(data));
+            }
+
+            template <typename T>
+            inline void add_to_queue(osmium::thread::Queue<std::future<T>>& queue, std::exception_ptr&& exception) {
+                std::promise<T> promise;
+                queue.push(promise.get_future());
+                promise.set_exception(std::move(exception));
+            }
+
+            template <typename T>
+            inline void add_end_of_data_to_queue(osmium::thread::Queue<std::future<T>>& queue) {
+                add_to_queue<T>(queue, T{});
+            }
+
+            inline bool at_end_of_data(const std::string& data) {
+                return data.empty();
+            }
+
+            inline bool at_end_of_data(osmium::memory::Buffer& buffer) {
+                return !buffer;
+            }
+
+            template <typename T>
+            class queue_wrapper {
+
+                using queue_type = osmium::thread::Queue<std::future<T>>;
+
+                queue_type& m_queue;
+                bool m_has_reached_end_of_data;
+
+            public:
+
+                queue_wrapper(queue_type& queue) :
+                    m_queue(queue),
+                    m_has_reached_end_of_data(false) {
+                }
+
+                ~queue_wrapper() noexcept {
+                    drain();
+                }
+
+                void drain() {
+                    while (!m_has_reached_end_of_data) {
+                        try {
+                            pop();
+                        } catch (...) {
+                            // Ignore any exceptions.
+                        }
+                    }
+                }
+
+                bool has_reached_end_of_data() const noexcept {
+                    return m_has_reached_end_of_data;
+                }
+
+                T pop() {
+                    T data;
+                    if (!m_has_reached_end_of_data) {
+                        std::future<T> data_future;
+                        m_queue.wait_and_pop(data_future);
+                        data = std::move(data_future.get());
+                        if (at_end_of_data(data)) {
+                            m_has_reached_end_of_data = true;
+                        }
+                    }
+                    return data;
+                }
+
+            }; // class queue_wrapper
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_QUEUE_UTIL_HPP
diff --git a/contrib/libosmium/osmium/io/detail/read_thread.hpp b/contrib/libosmium/osmium/io/detail/read_thread.hpp
new file mode 100644
index 0000000..6f96c0b
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/read_thread.hpp
@@ -0,0 +1,133 @@
+#ifndef OSMIUM_IO_DETAIL_READ_THREAD_HPP
+#define OSMIUM_IO_DETAIL_READ_THREAD_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <atomic>
+#include <exception>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/detail/queue_util.hpp>
+#include <osmium/thread/util.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            /**
+             * This code uses an internally managed thread to read data from
+             * the input file and (optionally) decompress it. The result is
+             * sent to the given queue. Any exceptions will also be send to
+             * the queue.
+             */
+            class ReadThreadManager {
+
+                // only used in the sub-thread
+                osmium::io::Decompressor& m_decompressor;
+                future_string_queue_type& m_queue;
+
+                // used in both threads
+                std::atomic<bool> m_done;
+
+                // only used in the main thread
+                std::thread m_thread;
+
+                void run_in_thread() {
+                    osmium::thread::set_thread_name("_osmium_read");
+
+                    try {
+                        while (!m_done) {
+                            std::string data {m_decompressor.read()};
+                            if (at_end_of_data(data)) {
+                                break;
+                            }
+                            add_to_queue(m_queue, std::move(data));
+                        }
+
+                        m_decompressor.close();
+                    } catch (...) {
+                        add_to_queue(m_queue, std::current_exception());
+                    }
+
+                    add_end_of_data_to_queue(m_queue);
+                }
+
+            public:
+
+                ReadThreadManager(osmium::io::Decompressor& decompressor,
+                                  future_string_queue_type& queue) :
+                    m_decompressor(decompressor),
+                    m_queue(queue),
+                    m_done(false),
+                    m_thread(std::thread(&ReadThreadManager::run_in_thread, this)) {
+                }
+
+                ReadThreadManager(const ReadThreadManager&) = delete;
+                ReadThreadManager& operator=(const ReadThreadManager&) = delete;
+
+                ReadThreadManager(ReadThreadManager&&) = delete;
+                ReadThreadManager& operator=(ReadThreadManager&&) = delete;
+
+                ~ReadThreadManager() noexcept {
+                    try {
+                        close();
+                    } catch (...) {
+                        // Ignore any exceptions because destructor must not throw.
+                    }
+                }
+
+                void stop() noexcept {
+                    m_done = true;
+                }
+
+                void close() {
+                    stop();
+                    if (m_thread.joinable()) {
+                        m_thread.join();
+                    }
+                }
+
+            }; // class ReadThreadManager
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_READ_THREAD_HPP
diff --git a/contrib/libosmium/osmium/io/detail/read_write.hpp b/contrib/libosmium/osmium/io/detail/read_write.hpp
new file mode 100644
index 0000000..5d1fa26
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/read_write.hpp
@@ -0,0 +1,180 @@
+#ifndef OSMIUM_IO_DETAIL_READ_WRITE_HPP
+#define OSMIUM_IO_DETAIL_READ_WRITE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cerrno>
+#include <cstddef>
+#include <errno.h>
+#include <fcntl.h>
+#include <string>
+#include <system_error>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
+
+#include <osmium/io/writer_options.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        /**
+         * @brief Namespace for Osmium internal use
+         */
+        namespace detail {
+
+            /**
+             * Open file for writing. If the file exists, it is truncated, if
+             * not, it is created. If the file name is empty or "-", no file
+             * is opened and the stdout file descriptor (1) is returned.
+             *
+             * @param filename Name of file to be opened.
+             * @param allow_overwrite If the file exists, should it be overwritten?
+             * @returns File descriptor of open file.
+             * @throws system_error if the file can't be opened.
+             */
+            inline int open_for_writing(const std::string& filename, osmium::io::overwrite allow_overwrite = osmium::io::overwrite::no) {
+                if (filename == "" || filename == "-") {
+#ifdef _WIN32
+                    _setmode(1, _O_BINARY);
+#endif
+                    return 1; // stdout
+                } else {
+                    int flags = O_WRONLY | O_CREAT;
+                    if (allow_overwrite == osmium::io::overwrite::allow) {
+                        flags |= O_TRUNC;
+                    } else {
+                        flags |= O_EXCL;
+                    }
+#ifdef _WIN32
+                    flags |= O_BINARY;
+#endif
+                    int fd = ::open(filename.c_str(), flags, 0666);
+                    if (fd < 0) {
+                        throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
+                    }
+                    return fd;
+                }
+            }
+
+            /**
+             * Open file for reading. If the file name is empty or "-", no file
+             * is opened and the stdin file descriptor (0) is returned.
+             *
+             * @param filename Name of file to be opened.
+             * @returns File descriptor of open file.
+             * @throws system_error if the file can't be opened.
+             */
+            inline int open_for_reading(const std::string& filename) {
+                if (filename == "" || filename == "-") {
+                    return 0; // stdin
+                } else {
+                    int flags = O_RDONLY;
+#ifdef _WIN32
+                    flags |= O_BINARY;
+#endif
+                    int fd = ::open(filename.c_str(), flags);
+                    if (fd < 0) {
+                        throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
+                    }
+                    return fd;
+                }
+            }
+
+            /**
+             * Writes the given number of bytes from the output_buffer to the file descriptor.
+             * This is just a wrapper around write(2), because write(2) can write less than
+             * the given number of bytes.
+             *
+             * @param fd File descriptor.
+             * @param output_buffer Buffer with data to be written. Must be at least size bytes long.
+             * @param size Number of bytes to write.
+             * @throws std::system_error On error.
+             */
+            inline void reliable_write(const int fd, const unsigned char* output_buffer, const size_t size) {
+                constexpr size_t max_write = 100L * 1024L * 1024L; // Max 100 MByte per write
+                size_t offset = 0;
+                do {
+                    auto write_count = size - offset;
+                    if (write_count > max_write) {
+                        write_count = max_write;
+                    }
+                    auto length = ::write(fd, output_buffer + offset, static_cast<unsigned int>(write_count));
+                    if (length < 0) {
+                        throw std::system_error(errno, std::system_category(), "Write failed");
+                    }
+                    offset += static_cast<size_t>(length);
+                } while (offset < size);
+            }
+
+            /**
+             * Writes the given number of bytes from the output_buffer to the file descriptor.
+             * This is just a wrapper around write(2), because write(2) can write less than
+             * the given number of bytes.
+             *
+             * @param fd File descriptor.
+             * @param output_buffer Buffer with data to be written. Must be at least size bytes long.
+             * @param size Number of bytes to write.
+             * @throws std::system_error On error.
+             */
+            inline void reliable_write(const int fd, const char* output_buffer, const size_t size) {
+                reliable_write(fd, reinterpret_cast<const unsigned char*>(output_buffer), size);
+            }
+
+            inline void reliable_fsync(const int fd) {
+#ifdef _WIN32
+                if (_commit(fd) != 0) {
+#else
+                if (::fsync(fd) != 0) {
+#endif
+                    throw std::system_error(errno, std::system_category(), "Fsync failed");
+                }
+            }
+
+            inline void reliable_close(const int fd) {
+                if (::close(fd) != 0) {
+                    throw std::system_error(errno, std::system_category(), "Close failed");
+                }
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_READ_WRITE_HPP
diff --git a/contrib/libosmium/osmium/io/detail/string_table.hpp b/contrib/libosmium/osmium/io/detail/string_table.hpp
new file mode 100644
index 0000000..a23035d
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/string_table.hpp
@@ -0,0 +1,265 @@
+#ifndef OSMIUM_IO_DETAIL_STRING_TABLE_HPP
+#define OSMIUM_IO_DETAIL_STRING_TABLE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <iterator>
+#include <list>
+#include <map>
+#include <string>
+
+#include <osmium/io/detail/pbf.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            /**
+             * class StringStore
+             *
+             * Storage of lots of strings (const char *). Memory is allocated in chunks.
+             * If a string is added and there is no space in the current chunk, a new
+             * chunk will be allocated. Strings added to the store must not be larger
+             * than the chunk size.
+             *
+             * All memory is released when the destructor is called. There is no other way
+             * to release all or part of the memory.
+             *
+             */
+            class StringStore {
+
+                size_t m_chunk_size;
+
+                std::list<std::string> m_chunks;
+
+                void add_chunk() {
+                    m_chunks.push_front(std::string());
+                    m_chunks.front().reserve(m_chunk_size);
+                }
+
+            public:
+
+                StringStore(size_t chunk_size) :
+                    m_chunk_size(chunk_size),
+                    m_chunks() {
+                    add_chunk();
+                }
+
+                void clear() noexcept {
+                    m_chunks.erase(std::next(m_chunks.begin()), m_chunks.end());
+                    m_chunks.front().clear();
+                }
+
+                /**
+                 * Add a null terminated string to the store. This will
+                 * automatically get more memory if we are out.
+                 * Returns a pointer to the copy of the string we have
+                 * allocated.
+                 */
+                const char* add(const char* string) {
+                    size_t len = std::strlen(string) + 1;
+
+                    assert(len <= m_chunk_size);
+
+                    size_t chunk_len = m_chunks.front().size();
+                    if (chunk_len + len > m_chunks.front().capacity()) {
+                        add_chunk();
+                        chunk_len = 0;
+                    }
+
+                    m_chunks.front().append(string);
+                    m_chunks.front().append(1, '\0');
+
+                    return m_chunks.front().c_str() + chunk_len;
+                }
+
+                class const_iterator : public std::iterator<std::forward_iterator_tag, const char*> {
+
+                    typedef std::list<std::string>::const_iterator it_type;
+                    it_type m_it;
+                    const it_type m_last;
+                    const char* m_pos;
+
+                public:
+
+                    const_iterator(it_type it, it_type last) :
+                        m_it(it),
+                        m_last(last),
+                        m_pos(it == last ? nullptr : m_it->c_str()) {
+                    }
+
+                    const_iterator& operator++() {
+                        assert(m_it != m_last);
+                        auto last_pos = m_it->c_str() + m_it->size();
+                        while (m_pos != last_pos && *m_pos) ++m_pos;
+                        if (m_pos != last_pos) ++m_pos;
+                        if (m_pos == last_pos) {
+                            ++m_it;
+                            if (m_it != m_last) {
+                                m_pos = m_it->c_str();
+                            } else {
+                                m_pos = nullptr;
+                            }
+                        }
+                        return *this;
+                    }
+
+                    const_iterator operator++(int) {
+                        const_iterator tmp(*this);
+                        operator++();
+                        return tmp;
+                    }
+
+                    bool operator==(const const_iterator& rhs) const {
+                        return m_it == rhs.m_it && m_pos == rhs.m_pos;
+                    }
+
+                    bool operator!=(const const_iterator& rhs) const {
+                        return !(*this == rhs);
+                    }
+
+                    const char* operator*() const {
+                        assert(m_it != m_last);
+                        assert(m_pos != nullptr);
+                        return m_pos;
+                    }
+
+                }; // class const_iterator
+
+                const_iterator begin() const {
+                    if (m_chunks.front().empty()) {
+                        return end();
+                    }
+                    return const_iterator(m_chunks.begin(), m_chunks.end());
+                }
+
+                const_iterator end() const {
+                    return const_iterator(m_chunks.end(), m_chunks.end());
+                }
+
+                // These functions get you some idea how much memory was
+                // used.
+                size_t get_chunk_size() const noexcept {
+                    return m_chunk_size;
+                }
+
+                size_t get_chunk_count() const noexcept {
+                    return m_chunks.size();
+                }
+
+                size_t get_used_bytes_in_last_chunk() const noexcept {
+                    return m_chunks.front().size();
+                }
+
+            }; // class StringStore
+
+            struct StrComp {
+
+                bool operator()(const char* lhs, const char* rhs) const {
+                    return strcmp(lhs, rhs) < 0;
+                }
+
+            }; // struct StrComp
+
+            class StringTable {
+
+                // This is the maximum number of entries in a string table.
+                // This should never be reached in practice but we better
+                // make sure it doesn't. If we had max_uncompressed_blob_size
+                // many entries, we are sure they would never fit into a PBF
+                // Blob.
+                static constexpr const uint32_t max_entries = max_uncompressed_blob_size;
+
+                StringStore m_strings;
+                std::map<const char*, size_t, StrComp> m_index;
+                uint32_t m_size;
+
+            public:
+
+                StringTable() :
+                    m_strings(1024 * 1024),
+                    m_index(),
+                    m_size(0) {
+                    m_strings.add("");
+                }
+
+                void clear() {
+                    m_strings.clear();
+                    m_index.clear();
+                    m_size = 0;
+                    m_strings.add("");
+                }
+
+                uint32_t size() const noexcept {
+                    return m_size + 1;
+                }
+
+                uint32_t add(const char* s) {
+                    auto f = m_index.find(s);
+                    if (f != m_index.end()) {
+                        return uint32_t(f->second);
+                    }
+
+                    const char* cs = m_strings.add(s);
+                    m_index[cs] = ++m_size;
+
+                    if (m_size > max_entries) {
+                        throw osmium::pbf_error("string table has too many entries");
+                    }
+
+                    return m_size;
+                }
+
+                StringStore::const_iterator begin() const {
+                    return m_strings.begin();
+                }
+
+                StringStore::const_iterator end() const {
+                    return m_strings.end();
+                }
+
+            }; // class StringTable
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_STRING_TABLE_HPP
diff --git a/contrib/libosmium/osmium/io/detail/string_util.hpp b/contrib/libosmium/osmium/io/detail/string_util.hpp
new file mode 100644
index 0000000..672266a
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/string_util.hpp
@@ -0,0 +1,206 @@
+#ifndef OSMIUM_IO_DETAIL_STRING_UTIL_HPP
+#define OSMIUM_IO_DETAIL_STRING_UTIL_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <utility>
+
+#include <utf8.h>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+#ifndef _MSC_VER
+# define SNPRINTF std::snprintf
+#else
+# define SNPRINTF _snprintf
+#endif
+
+            template <typename... TArgs>
+            inline int string_snprintf(std::string& out,
+                                       size_t old_size,
+                                       size_t max_size,
+                                       const char* format,
+                                       TArgs&&... args) {
+                out.resize(old_size + max_size);
+
+                return SNPRINTF(max_size ? const_cast<char*>(out.c_str()) + old_size : nullptr,
+                                max_size,
+                                format,
+                                std::forward<TArgs>(args)...);
+            }
+
+#undef SNPRINTF
+
+            /**
+             * This is a helper function for writing printf-like formatted
+             * data into a std::string.
+             *
+             * @param out The data will be appended to this string.
+             * @param format A string with formatting instructions a la printf.
+             * @param args Any further arguments like in printf.
+             * @throws std::bad_alloc If the string needed to grow and there
+             *         wasn't enough memory.
+             */
+            template <typename... TArgs>
+            inline void append_printf_formatted_string(std::string& out,
+                                                   const char* format,
+                                                   TArgs&&... args) {
+
+                // First try to write string with the max_size, if that doesn't
+                // work snprintf will tell us how much space it needs. We
+                // reserve that much space and try again. So this will always
+                // work, even if the output is larger than the given max_size.
+                //
+                // Unfortunately this trick doesn't work on Windows, because
+                // the _snprintf() function there only returns the length it
+                // needs if max_size==0 and the buffer pointer is the null
+                // pointer. So we have to take this into account.
+
+#ifndef _MSC_VER
+                static const size_t max_size = 100;
+#else
+                static const size_t max_size = 0;
+#endif
+
+                size_t old_size = out.size();
+
+                int len = string_snprintf(out,
+                                          old_size,
+                                          max_size,
+                                          format,
+                                          std::forward<TArgs>(args)...);
+                assert(len > 0);
+
+                if (size_t(len) >= max_size) {
+                    int len2 = string_snprintf(out,
+                                               old_size,
+                                               size_t(len) + 1,
+                                               format,
+                                               std::forward<TArgs>(args)...);
+                    assert(len2 == len);
+                }
+
+                out.resize(old_size + size_t(len));
+            }
+
+            inline void append_utf8_encoded_string(std::string& out, const char* data) {
+                const char* end = data + std::strlen(data);
+
+                while (data != end) {
+                    const char* last = data;
+                    uint32_t c = utf8::next(data, end);
+
+                    // This is a list of Unicode code points that we let
+                    // through instead of escaping them. It is incomplete
+                    // and can be extended later.
+                    // Generally we don't want to let through any character
+                    // that has special meaning in the OPL format such as
+                    // space, comma, @, etc. and any non-printing characters.
+                    if ((0x0021 <= c && c <= 0x0024) ||
+                        (0x0026 <= c && c <= 0x002b) ||
+                        (0x002d <= c && c <= 0x003c) ||
+                        (0x003e <= c && c <= 0x003f) ||
+                        (0x0041 <= c && c <= 0x007e) ||
+                        (0x00a1 <= c && c <= 0x00ac) ||
+                        (0x00ae <= c && c <= 0x05ff)) {
+                        out.append(last, data);
+                    } else {
+                        out += '%';
+                        if (c <= 0xff) {
+                            append_printf_formatted_string(out, "%02x", c);
+                        } else {
+                            append_printf_formatted_string(out, "%04x", c);
+                        }
+                        out += '%';
+                    }
+                }
+            }
+
+            inline void append_xml_encoded_string(std::string& out, const char* data) {
+                for (; *data != '\0'; ++data) {
+                    switch(*data) {
+                        case '&':  out += "&";  break;
+                        case '\"': out += """; break;
+                        case '\'': out += "'"; break;
+                        case '<':  out += "<";   break;
+                        case '>':  out += ">";   break;
+                        case '\n': out += "&#xA;";  break;
+                        case '\r': out += "&#xD;";  break;
+                        case '\t': out += "&#x9;";  break;
+                        default:   out += *data;    break;
+                    }
+                }
+            }
+
+            inline void append_debug_encoded_string(std::string& out, const char* data, const char* prefix, const char* suffix) {
+                const char* end = data + std::strlen(data);
+
+                while (data != end) {
+                    const char* last = data;
+                    uint32_t c = utf8::next(data, end);
+
+                    // This is a list of Unicode code points that we let
+                    // through instead of escaping them. It is incomplete
+                    // and can be extended later.
+                    // Generally we don't want to let through any
+                    // non-printing characters.
+                    if ((0x0020 <= c && c <= 0x0021) ||
+                        (0x0023 <= c && c <= 0x003b) ||
+                        (0x003d == c) ||
+                        (0x003f <= c && c <= 0x007e) ||
+                        (0x00a1 <= c && c <= 0x00ac) ||
+                        (0x00ae <= c && c <= 0x05ff)) {
+                        out.append(last, data);
+                    } else {
+                        out.append(prefix);
+                        append_printf_formatted_string(out, "<U+%04X>", c);
+                        out.append(suffix);
+                    }
+                }
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_STRING_UTIL_HPP
diff --git a/contrib/libosmium/osmium/io/detail/write_thread.hpp b/contrib/libosmium/osmium/io/detail/write_thread.hpp
new file mode 100644
index 0000000..81ab194
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/write_thread.hpp
@@ -0,0 +1,107 @@
+#ifndef OSMIUM_IO_DETAIL_WRITE_THREAD_HPP
+#define OSMIUM_IO_DETAIL_WRITE_THREAD_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <exception>
+#include <future>
+#include <string>
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/detail/queue_util.hpp>
+#include <osmium/thread/util.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            /**
+             * This codes runs in its own thread, getting data from the given
+             * queue, (optionally) compressing it, and writing it to the output
+             * file.
+             */
+            class WriteThread {
+
+                queue_wrapper<std::string> m_queue;
+                std::unique_ptr<osmium::io::Compressor> m_compressor;
+                std::promise<bool> m_promise;
+
+            public:
+
+                WriteThread(future_string_queue_type& input_queue,
+                            std::unique_ptr<osmium::io::Compressor>&& compressor,
+                            std::promise<bool>&& promise) :
+                    m_queue(input_queue),
+                    m_compressor(std::move(compressor)),
+                    m_promise(std::move(promise)) {
+                }
+
+                WriteThread(const WriteThread&) = delete;
+                WriteThread& operator=(const WriteThread&) = delete;
+
+                WriteThread(WriteThread&&) = delete;
+                WriteThread& operator=(WriteThread&&) = delete;
+
+                ~WriteThread() noexcept = default;
+
+                void operator()() {
+                    osmium::thread::set_thread_name("_osmium_write");
+
+                    try {
+                        while (true) {
+                            std::string data = m_queue.pop();
+                            if (at_end_of_data(data)) {
+                                break;
+                            }
+                            m_compressor->write(data);
+                        }
+                        m_compressor->close();
+                        m_promise.set_value(true);
+                    } catch (...) {
+                        m_promise.set_exception(std::current_exception());
+                        m_queue.drain();
+                    }
+                }
+
+            }; // class WriteThread
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_WRITE_THREAD_HPP
diff --git a/contrib/libosmium/osmium/io/detail/xml_input_format.hpp b/contrib/libosmium/osmium/io/detail/xml_input_format.hpp
new file mode 100644
index 0000000..45dbde0
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/xml_input_format.hpp
@@ -0,0 +1,679 @@
+#ifndef OSMIUM_IO_DETAIL_XML_INPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_XML_INPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <exception>
+#include <future>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <expat.h>
+
+#include <osmium/builder/builder.hpp>
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/io/detail/input_format.hpp>
+#include <osmium/io/detail/queue_util.hpp>
+#include <osmium/io/error.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/types_from_string.hpp>
+#include <osmium/thread/queue.hpp>
+#include <osmium/thread/util.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when the XML parser failed. The exception contains
+     * (if available) information about the place where the error happened
+     * and the type of error.
+     */
+    struct xml_error : public io_error {
+
+        unsigned long line;
+        unsigned long column;
+        XML_Error error_code;
+        std::string error_string;
+
+        explicit xml_error(XML_Parser parser) :
+            io_error(std::string("XML parsing error at line ")
+                    + std::to_string(XML_GetCurrentLineNumber(parser))
+                    + ", column "
+                    + std::to_string(XML_GetCurrentColumnNumber(parser))
+                    + ": "
+                    + XML_ErrorString(XML_GetErrorCode(parser))),
+            line(XML_GetCurrentLineNumber(parser)),
+            column(XML_GetCurrentColumnNumber(parser)),
+            error_code(XML_GetErrorCode(parser)),
+            error_string(XML_ErrorString(error_code)) {
+        }
+
+        explicit xml_error(const std::string& message) :
+            io_error(message),
+            line(0),
+            column(0),
+            error_code(),
+            error_string(message) {
+        }
+
+    }; // struct xml_error
+
+    /**
+     * Exception thrown when an OSM XML files contains no version attribute
+     * on the 'osm' element or if the version is unknown.
+     */
+    struct format_version_error : public io_error {
+
+        std::string version;
+
+        explicit format_version_error() :
+            io_error("Can not read file without version (missing version attribute on osm element)."),
+            version() {
+        }
+
+        explicit format_version_error(const char* v) :
+            io_error(std::string("Can not read file with version ") + v),
+            version(v) {
+        }
+
+    }; // struct format_version_error
+
+    namespace io {
+
+        namespace detail {
+
+            class XMLParser : public Parser {
+
+                static constexpr int buffer_size = 2 * 1000 * 1000;
+
+                enum class context {
+                    root,
+                    top,
+                    node,
+                    way,
+                    relation,
+                    changeset,
+                    discussion,
+                    comment,
+                    comment_text,
+                    ignored_node,
+                    ignored_way,
+                    ignored_relation,
+                    ignored_changeset,
+                    in_object
+                }; // enum class context
+
+                context m_context;
+                context m_last_context;
+
+                /**
+                 * This is used only for change files which contain create, modify,
+                 * and delete sections.
+                 */
+                bool m_in_delete_section;
+
+                osmium::io::Header m_header;
+
+                osmium::memory::Buffer m_buffer;
+
+                std::unique_ptr<osmium::builder::NodeBuilder>                m_node_builder;
+                std::unique_ptr<osmium::builder::WayBuilder>                 m_way_builder;
+                std::unique_ptr<osmium::builder::RelationBuilder>            m_relation_builder;
+                std::unique_ptr<osmium::builder::ChangesetBuilder>           m_changeset_builder;
+                std::unique_ptr<osmium::builder::ChangesetDiscussionBuilder> m_changeset_discussion_builder;
+
+                std::unique_ptr<osmium::builder::TagListBuilder>             m_tl_builder;
+                std::unique_ptr<osmium::builder::WayNodeListBuilder>         m_wnl_builder;
+                std::unique_ptr<osmium::builder::RelationMemberListBuilder>  m_rml_builder;
+
+                std::string m_comment_text;
+
+                /**
+                 * A C++ wrapper for the Expat parser that makes sure no memory is leaked.
+                 */
+                template <typename T>
+                class ExpatXMLParser {
+
+                    XML_Parser m_parser;
+
+                    static void XMLCALL start_element_wrapper(void* data, const XML_Char* element, const XML_Char** attrs) {
+                        static_cast<XMLParser*>(data)->start_element(element, attrs);
+                    }
+
+                    static void XMLCALL end_element_wrapper(void* data, const XML_Char* element) {
+                        static_cast<XMLParser*>(data)->end_element(element);
+                    }
+
+                    static void XMLCALL character_data_wrapper(void* data, const XML_Char* text, int len) {
+                        static_cast<XMLParser*>(data)->characters(text, len);
+                    }
+
+                public:
+
+                    ExpatXMLParser(T* callback_object) :
+                        m_parser(XML_ParserCreate(nullptr)) {
+                        if (!m_parser) {
+                            throw osmium::io_error("Internal error: Can not create parser");
+                        }
+                        XML_SetUserData(m_parser, callback_object);
+                        XML_SetElementHandler(m_parser, start_element_wrapper, end_element_wrapper);
+                        XML_SetCharacterDataHandler(m_parser, character_data_wrapper);
+                    }
+
+                    ExpatXMLParser(const ExpatXMLParser&) = delete;
+                    ExpatXMLParser(ExpatXMLParser&&) = delete;
+
+                    ExpatXMLParser& operator=(const ExpatXMLParser&) = delete;
+                    ExpatXMLParser& operator=(ExpatXMLParser&&) = delete;
+
+                    ~ExpatXMLParser() noexcept {
+                        XML_ParserFree(m_parser);
+                    }
+
+                    void operator()(const std::string& data, bool last) {
+                        if (XML_Parse(m_parser, data.data(), static_cast_with_assert<int>(data.size()), last) == XML_STATUS_ERROR) {
+                            throw osmium::xml_error(m_parser);
+                        }
+                    }
+
+                }; // class ExpatXMLParser
+
+                template <typename T>
+                static void check_attributes(const XML_Char** attrs, T check) {
+                    while (*attrs) {
+                        check(attrs[0], attrs[1]);
+                        attrs += 2;
+                    }
+                }
+
+                const char* init_object(osmium::OSMObject& object, const XML_Char** attrs) {
+                    const char* user = "";
+
+                    if (m_in_delete_section) {
+                        object.set_visible(false);
+                    }
+
+                    osmium::Location location;
+
+                    check_attributes(attrs, [&location, &user, &object](const XML_Char* name, const XML_Char* value) {
+                        if (!strcmp(name, "lon")) {
+                            location.set_lon(std::atof(value)); // XXX doesn't detect garbage after the number
+                        } else if (!strcmp(name, "lat")) {
+                            location.set_lat(std::atof(value)); // XXX doesn't detect garbage after the number
+                        } else if (!strcmp(name, "user")) {
+                            user = value;
+                        } else {
+                            object.set_attribute(name, value);
+                        }
+                    });
+
+                    if (location && object.type() == osmium::item_type::node) {
+                        static_cast<osmium::Node&>(object).set_location(location);
+                    }
+
+                    return user;
+                }
+
+                void init_changeset(osmium::builder::ChangesetBuilder* builder, const XML_Char** attrs) {
+                    const char* user = "";
+                    osmium::Changeset& new_changeset = builder->object();
+
+                    osmium::Location min;
+                    osmium::Location max;
+                    check_attributes(attrs, [&min, &max, &user, &new_changeset](const XML_Char* name, const XML_Char* value) {
+                        if (!strcmp(name, "min_lon")) {
+                            min.set_lon(atof(value));
+                        } else if (!strcmp(name, "min_lat")) {
+                            min.set_lat(atof(value));
+                        } else if (!strcmp(name, "max_lon")) {
+                            max.set_lon(atof(value));
+                        } else if (!strcmp(name, "max_lat")) {
+                            max.set_lat(atof(value));
+                        } else if (!strcmp(name, "user")) {
+                            user = value;
+                        } else {
+                            new_changeset.set_attribute(name, value);
+                        }
+                    });
+
+                    new_changeset.bounds().extend(min);
+                    new_changeset.bounds().extend(max);
+
+                    builder->add_user(user);
+                }
+
+                void get_tag(osmium::builder::Builder* builder, const XML_Char** attrs) {
+                    const char* k = "";
+                    const char* v = "";
+                    check_attributes(attrs, [&k, &v](const XML_Char* name, const XML_Char* value) {
+                        if (name[0] == 'k' && name[1] == 0) {
+                            k = value;
+                        } else if (name[0] == 'v' && name[1] == 0) {
+                            v = value;
+                        }
+                    });
+                    if (!m_tl_builder) {
+                        m_tl_builder = std::unique_ptr<osmium::builder::TagListBuilder>(new osmium::builder::TagListBuilder(m_buffer, builder));
+                    }
+                    m_tl_builder->add_tag(k, v);
+                }
+
+                void mark_header_as_done() {
+                    set_header_value(m_header);
+                }
+
+                void start_element(const XML_Char* element, const XML_Char** attrs) {
+                    switch (m_context) {
+                        case context::root:
+                            if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) {
+                                if (!strcmp(element, "osmChange")) {
+                                    m_header.set_has_multiple_object_versions(true);
+                                }
+                                check_attributes(attrs, [this](const XML_Char* name, const XML_Char* value) {
+                                    if (!strcmp(name, "version")) {
+                                        m_header.set("version", value);
+                                        if (strcmp(value, "0.6")) {
+                                            throw osmium::format_version_error(value);
+                                        }
+                                    } else if (!strcmp(name, "generator")) {
+                                        m_header.set("generator", value);
+                                    }
+                                });
+                                if (m_header.get("version") == "") {
+                                    throw osmium::format_version_error();
+                                }
+                            } else {
+                                throw osmium::xml_error(std::string("Unknown top-level element: ") + element);
+                            }
+                            m_context = context::top;
+                            break;
+                        case context::top:
+                            assert(!m_tl_builder);
+                            if (!strcmp(element, "node")) {
+                                mark_header_as_done();
+                                if (read_types() & osmium::osm_entity_bits::node) {
+                                    m_node_builder = std::unique_ptr<osmium::builder::NodeBuilder>(new osmium::builder::NodeBuilder(m_buffer));
+                                    m_node_builder->add_user(init_object(m_node_builder->object(), attrs));
+                                    m_context = context::node;
+                                } else {
+                                    m_context = context::ignored_node;
+                                }
+                            } else if (!strcmp(element, "way")) {
+                                mark_header_as_done();
+                                if (read_types() & osmium::osm_entity_bits::way) {
+                                    m_way_builder = std::unique_ptr<osmium::builder::WayBuilder>(new osmium::builder::WayBuilder(m_buffer));
+                                    m_way_builder->add_user(init_object(m_way_builder->object(), attrs));
+                                    m_context = context::way;
+                                } else {
+                                    m_context = context::ignored_way;
+                                }
+                            } else if (!strcmp(element, "relation")) {
+                                mark_header_as_done();
+                                if (read_types() & osmium::osm_entity_bits::relation) {
+                                    m_relation_builder = std::unique_ptr<osmium::builder::RelationBuilder>(new osmium::builder::RelationBuilder(m_buffer));
+                                    m_relation_builder->add_user(init_object(m_relation_builder->object(), attrs));
+                                    m_context = context::relation;
+                                } else {
+                                    m_context = context::ignored_relation;
+                                }
+                            } else if (!strcmp(element, "changeset")) {
+                                mark_header_as_done();
+                                if (read_types() & osmium::osm_entity_bits::changeset) {
+                                    m_changeset_builder = std::unique_ptr<osmium::builder::ChangesetBuilder>(new osmium::builder::ChangesetBuilder(m_buffer));
+                                    init_changeset(m_changeset_builder.get(), attrs);
+                                    m_context = context::changeset;
+                                } else {
+                                    m_context = context::ignored_changeset;
+                                }
+                            } else if (!strcmp(element, "bounds")) {
+                                osmium::Location min;
+                                osmium::Location max;
+                                check_attributes(attrs, [&min, &max](const XML_Char* name, const XML_Char* value) {
+                                    if (!strcmp(name, "minlon")) {
+                                        min.set_lon(atof(value));
+                                    } else if (!strcmp(name, "minlat")) {
+                                        min.set_lat(atof(value));
+                                    } else if (!strcmp(name, "maxlon")) {
+                                        max.set_lon(atof(value));
+                                    } else if (!strcmp(name, "maxlat")) {
+                                        max.set_lat(atof(value));
+                                    }
+                                });
+                                osmium::Box box;
+                                box.extend(min).extend(max);
+                                m_header.add_box(box);
+                            } else if (!strcmp(element, "delete")) {
+                                m_in_delete_section = true;
+                            }
+                            break;
+                        case context::node:
+                            m_last_context = context::node;
+                            m_context = context::in_object;
+                            if (!strcmp(element, "tag")) {
+                                get_tag(m_node_builder.get(), attrs);
+                            }
+                            break;
+                        case context::way:
+                            m_last_context = context::way;
+                            m_context = context::in_object;
+                            if (!strcmp(element, "nd")) {
+                                m_tl_builder.reset();
+
+                                if (!m_wnl_builder) {
+                                    m_wnl_builder = std::unique_ptr<osmium::builder::WayNodeListBuilder>(new osmium::builder::WayNodeListBuilder(m_buffer, m_way_builder.get()));
+                                }
+
+                                check_attributes(attrs, [this](const XML_Char* name, const XML_Char* value) {
+                                    if (!strcmp(name, "ref")) {
+                                        m_wnl_builder->add_node_ref(osmium::string_to_object_id(value));
+                                    }
+                                });
+                            } else if (!strcmp(element, "tag")) {
+                                m_wnl_builder.reset();
+                                get_tag(m_way_builder.get(), attrs);
+                            }
+                            break;
+                        case context::relation:
+                            m_last_context = context::relation;
+                            m_context = context::in_object;
+                            if (!strcmp(element, "member")) {
+                                m_tl_builder.reset();
+
+                                if (!m_rml_builder) {
+                                    m_rml_builder = std::unique_ptr<osmium::builder::RelationMemberListBuilder>(new osmium::builder::RelationMemberListBuilder(m_buffer, m_relation_builder.get()));
+                                }
+
+                                item_type type = item_type::undefined;
+                                object_id_type ref = 0;
+                                const char* role = "";
+                                check_attributes(attrs, [&type, &ref, &role](const XML_Char* name, const XML_Char* value) {
+                                    if (!strcmp(name, "type")) {
+                                        type = char_to_item_type(value[0]);
+                                    } else if (!strcmp(name, "ref")) {
+                                        ref = osmium::string_to_object_id(value);
+                                    } else if (!strcmp(name, "role")) {
+                                        role = static_cast<const char*>(value);
+                                    }
+                                });
+                                if (type != item_type::node && type != item_type::way && type != item_type::relation) {
+                                    throw osmium::xml_error("Unknown type on relation member");
+                                }
+                                if (ref == 0) {
+                                    throw osmium::xml_error("Missing ref on relation member");
+                                }
+                                m_rml_builder->add_member(type, ref, role);
+                            } else if (!strcmp(element, "tag")) {
+                                m_rml_builder.reset();
+                                get_tag(m_relation_builder.get(), attrs);
+                            }
+                            break;
+                        case context::changeset:
+                            m_last_context = context::changeset;
+                            if (!strcmp(element, "discussion")) {
+                                m_context = context::discussion;
+                                m_tl_builder.reset();
+                                if (!m_changeset_discussion_builder) {
+                                    m_changeset_discussion_builder = std::unique_ptr<osmium::builder::ChangesetDiscussionBuilder>(new osmium::builder::ChangesetDiscussionBuilder(m_buffer, m_changeset_builder.get()));
+                                }
+                            } else if (!strcmp(element, "tag")) {
+                                m_context = context::in_object;
+                                m_changeset_discussion_builder.reset();
+                                get_tag(m_changeset_builder.get(), attrs);
+                            }
+                            break;
+                        case context::discussion:
+                            if (!strcmp(element, "comment")) {
+                                m_context = context::comment;
+                                osmium::Timestamp date;
+                                osmium::user_id_type uid = 0;
+                                const char* user = "";
+                                check_attributes(attrs, [&date, &uid, &user](const XML_Char* name, const XML_Char* value) {
+                                    if (!strcmp(name, "date")) {
+                                        date = osmium::Timestamp(value);
+                                    } else if (!strcmp(name, "uid")) {
+                                        uid = osmium::string_to_user_id(value);
+                                    } else if (!strcmp(name, "user")) {
+                                        user = static_cast<const char*>(value);
+                                    }
+                                });
+                                m_changeset_discussion_builder->add_comment(date, uid, user);
+                            }
+                            break;
+                        case context::comment:
+                            if (!strcmp(element, "text")) {
+                                m_context = context::comment_text;
+                            }
+                            break;
+                        case context::comment_text:
+                            break;
+                        case context::ignored_node:
+                            break;
+                        case context::ignored_way:
+                            break;
+                        case context::ignored_relation:
+                            break;
+                        case context::ignored_changeset:
+                            break;
+                        case context::in_object:
+                            assert(false); // should never be here
+                            break;
+                    }
+                }
+
+                void end_element(const XML_Char* element) {
+                    switch (m_context) {
+                        case context::root:
+                            assert(false); // should never be here
+                            break;
+                        case context::top:
+                            if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) {
+                                mark_header_as_done();
+                                m_context = context::root;
+                            } else if (!strcmp(element, "delete")) {
+                                m_in_delete_section = false;
+                            }
+                            break;
+                        case context::node:
+                            assert(!strcmp(element, "node"));
+                            m_tl_builder.reset();
+                            m_node_builder.reset();
+                            m_buffer.commit();
+                            m_context = context::top;
+                            flush_buffer();
+                            break;
+                        case context::way:
+                            assert(!strcmp(element, "way"));
+                            m_tl_builder.reset();
+                            m_wnl_builder.reset();
+                            m_way_builder.reset();
+                            m_buffer.commit();
+                            m_context = context::top;
+                            flush_buffer();
+                            break;
+                        case context::relation:
+                            assert(!strcmp(element, "relation"));
+                            m_tl_builder.reset();
+                            m_rml_builder.reset();
+                            m_relation_builder.reset();
+                            m_buffer.commit();
+                            m_context = context::top;
+                            flush_buffer();
+                            break;
+                        case context::changeset:
+                            assert(!strcmp(element, "changeset"));
+                            m_tl_builder.reset();
+                            m_changeset_discussion_builder.reset();
+                            m_changeset_builder.reset();
+                            m_buffer.commit();
+                            m_context = context::top;
+                            flush_buffer();
+                            break;
+                        case context::discussion:
+                            assert(!strcmp(element, "discussion"));
+                            m_context = context::changeset;
+                            break;
+                        case context::comment:
+                            assert(!strcmp(element, "comment"));
+                            m_context = context::discussion;
+                            break;
+                        case context::comment_text:
+                            assert(!strcmp(element, "text"));
+                            m_context = context::comment;
+                            m_changeset_discussion_builder->add_comment_text(m_comment_text);
+                            break;
+                        case context::in_object:
+                            m_context = m_last_context;
+                            break;
+                        case context::ignored_node:
+                            if (!strcmp(element, "node")) {
+                                m_context = context::top;
+                            }
+                            break;
+                        case context::ignored_way:
+                            if (!strcmp(element, "way")) {
+                                m_context = context::top;
+                            }
+                            break;
+                        case context::ignored_relation:
+                            if (!strcmp(element, "relation")) {
+                                m_context = context::top;
+                            }
+                            break;
+                        case context::ignored_changeset:
+                            if (!strcmp(element, "changeset")) {
+                                m_context = context::top;
+                            }
+                            break;
+                    }
+                }
+
+                void characters(const XML_Char* text, int len) {
+                    if (m_context == context::comment_text) {
+                        m_comment_text.append(text, len);
+                    } else {
+                        m_comment_text.resize(0);
+                    }
+                }
+
+                void flush_buffer() {
+                    if (m_buffer.committed() > buffer_size / 10 * 9) {
+                        send_to_output_queue(std::move(m_buffer));
+                        osmium::memory::Buffer buffer(buffer_size);
+                        using std::swap;
+                        swap(m_buffer, buffer);
+                    }
+                }
+
+            public:
+
+                XMLParser(future_string_queue_type& input_queue,
+                          future_buffer_queue_type& output_queue,
+                          std::promise<osmium::io::Header>& header_promise,
+                          osmium::osm_entity_bits::type read_types) :
+                    Parser(input_queue, output_queue, header_promise, read_types),
+                    m_context(context::root),
+                    m_last_context(context::root),
+                    m_in_delete_section(false),
+                    m_header(),
+                    m_buffer(buffer_size),
+                    m_node_builder(),
+                    m_way_builder(),
+                    m_relation_builder(),
+                    m_changeset_builder(),
+                    m_changeset_discussion_builder(),
+                    m_tl_builder(),
+                    m_wnl_builder(),
+                    m_rml_builder() {
+                }
+
+                ~XMLParser() noexcept = default;
+
+                void run() override final {
+                    osmium::thread::set_thread_name("_osmium_xml_in");
+
+                    ExpatXMLParser<XMLParser> parser(this);
+
+                    while (!input_done()) {
+                        std::string data = get_input();
+                        parser(data, input_done());
+                        if (read_types() == osmium::osm_entity_bits::nothing && header_is_done()) {
+                            break;
+                        }
+                    }
+
+                    mark_header_as_done();
+
+                    if (m_buffer.committed() > 0) {
+                        send_to_output_queue(std::move(m_buffer));
+                    }
+                }
+
+            }; // class XMLParser
+
+            // we want the register_parser() function to run, setting
+            // the variable is only a side-effect, it will never be used
+            const bool registered_xml_parser = ParserFactory::instance().register_parser(
+                file_format::xml,
+                [](future_string_queue_type& input_queue,
+                    future_buffer_queue_type& output_queue,
+                    std::promise<osmium::io::Header>& header_promise,
+                    osmium::osm_entity_bits::type read_which_entities) {
+                    return std::unique_ptr<Parser>(new XMLParser(input_queue, output_queue, header_promise, read_which_entities));
+            });
+
+            // dummy function to silence the unused variable warning from above
+            inline bool get_registered_xml_parser() noexcept {
+                return registered_xml_parser;
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_XML_INPUT_FORMAT_HPP
diff --git a/contrib/libosmium/osmium/io/detail/xml_output_format.hpp b/contrib/libosmium/osmium/io/detail/xml_output_format.hpp
new file mode 100644
index 0000000..b91b051
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/xml_output_format.hpp
@@ -0,0 +1,473 @@
+#ifndef OSMIUM_IO_DETAIL_XML_OUTPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_XML_OUTPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cinttypes>
+#include <cstddef>
+#include <cstdio>
+#include <future>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/changeset.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/thread/pool.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            struct XMLWriteError {};
+
+            struct xml_output_options {
+
+                /// Should metadata of objects be added?
+                bool add_metadata;
+
+                /// Should the visible flag be added to all OSM objects?
+                bool add_visible_flag;
+
+                /**
+                 * Should <create>, <modify>, <delete> "operations" be added?
+                 * (This is used for .osc files.)
+                 */
+                bool use_change_ops;
+
+            };
+
+            class XMLOutputBlock : public OutputBlock {
+
+                // operation (create, modify, delete) for osc files
+                enum class operation {
+                    op_none   = 0,
+                    op_create = 1,
+                    op_modify = 2,
+                    op_delete = 3
+                }; // enum class operation
+
+                operation m_last_op {operation::op_none};
+
+                xml_output_options m_options;
+
+                void write_spaces(int num) {
+                    for (; num != 0; --num) {
+                        *m_out += ' ';
+                    }
+                }
+
+                int prefix_spaces() {
+                    return m_options.use_change_ops ? 4 : 2;
+                }
+
+                void write_prefix() {
+                    write_spaces(prefix_spaces());
+                }
+
+                void write_meta(const osmium::OSMObject& object) {
+                    output_formatted(" id=\"%" PRId64 "\"", object.id());
+
+                    if (m_options.add_metadata) {
+                        if (object.version()) {
+                            output_formatted(" version=\"%d\"", object.version());
+                        }
+
+                        if (object.timestamp()) {
+                            *m_out += " timestamp=\"";
+                            *m_out += object.timestamp().to_iso();
+                            *m_out += "\"";
+                        }
+
+                        if (!object.user_is_anonymous()) {
+                            output_formatted(" uid=\"%d\" user=\"", object.uid());
+                            append_xml_encoded_string(*m_out, object.user());
+                            *m_out += "\"";
+                        }
+
+                        if (object.changeset()) {
+                            output_formatted(" changeset=\"%d\"", object.changeset());
+                        }
+
+                        if (m_options.add_visible_flag) {
+                            if (object.visible()) {
+                                *m_out += " visible=\"true\"";
+                            } else {
+                                *m_out += " visible=\"false\"";
+                            }
+                        }
+                    }
+                }
+
+                void write_tags(const osmium::TagList& tags, int spaces) {
+                    for (const auto& tag : tags) {
+                        write_spaces(spaces);
+                        *m_out += "  <tag k=\"";
+                        append_xml_encoded_string(*m_out, tag.key());
+                        *m_out += "\" v=\"";
+                        append_xml_encoded_string(*m_out, tag.value());
+                        *m_out += "\"/>\n";
+                    }
+                }
+
+                void write_discussion(const osmium::ChangesetDiscussion& comments) {
+                    for (const auto& comment : comments) {
+                        output_formatted("   <comment uid=\"%d\" user=\"", comment.uid());
+                        append_xml_encoded_string(*m_out, comment.user());
+                        *m_out += "\" date=\"";
+                        *m_out += comment.date().to_iso();
+                        *m_out += "\">\n";
+                        *m_out += "    <text>";
+                        append_xml_encoded_string(*m_out, comment.text());
+                        *m_out += "</text>\n   </comment>\n";
+                    }
+                    *m_out += "  </discussion>\n";
+                }
+
+                void open_close_op_tag(const operation op = operation::op_none) {
+                    if (op == m_last_op) {
+                        return;
+                    }
+
+                    switch (m_last_op) {
+                        case operation::op_none:
+                            break;
+                        case operation::op_create:
+                            *m_out += "  </create>\n";
+                            break;
+                        case operation::op_modify:
+                            *m_out += "  </modify>\n";
+                            break;
+                        case operation::op_delete:
+                            *m_out += "  </delete>\n";
+                            break;
+                    }
+
+                    switch (op) {
+                        case operation::op_none:
+                            break;
+                        case operation::op_create:
+                            *m_out += "  <create>\n";
+                            break;
+                        case operation::op_modify:
+                            *m_out += "  <modify>\n";
+                            break;
+                        case operation::op_delete:
+                            *m_out += "  <delete>\n";
+                            break;
+                    }
+
+                    m_last_op = op;
+                }
+
+            public:
+
+                XMLOutputBlock(osmium::memory::Buffer&& buffer, const xml_output_options& options) :
+                    OutputBlock(std::move(buffer)),
+                    m_options(options) {
+                }
+
+                XMLOutputBlock(const XMLOutputBlock&) = default;
+                XMLOutputBlock& operator=(const XMLOutputBlock&) = default;
+
+                XMLOutputBlock(XMLOutputBlock&&) = default;
+                XMLOutputBlock& operator=(XMLOutputBlock&&) = default;
+
+                ~XMLOutputBlock() noexcept = default;
+
+                std::string operator()() {
+                    osmium::apply(m_input_buffer->cbegin(), m_input_buffer->cend(), *this);
+
+                    if (m_options.use_change_ops) {
+                        open_close_op_tag();
+                    }
+
+                    std::string out;
+                    using std::swap;
+                    swap(out, *m_out);
+
+                    return out;
+                }
+
+                void node(const osmium::Node& node) {
+                    if (m_options.use_change_ops) {
+                        open_close_op_tag(node.visible() ? (node.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
+                    }
+
+                    write_prefix();
+                    *m_out += "<node";
+
+                    write_meta(node);
+
+                    if (node.location()) {
+                        *m_out += " lat=\"";
+                        osmium::util::double2string(std::back_inserter(*m_out), node.location().lat_without_check(), 7);
+                        *m_out += "\" lon=\"";
+                        osmium::util::double2string(std::back_inserter(*m_out), node.location().lon_without_check(), 7);
+                        *m_out += "\"";
+                    }
+
+                    if (node.tags().empty()) {
+                        *m_out += "/>\n";
+                        return;
+                    }
+
+                    *m_out += ">\n";
+
+                    write_tags(node.tags(), prefix_spaces());
+
+                    write_prefix();
+                    *m_out += "</node>\n";
+                }
+
+                void way(const osmium::Way& way) {
+                    if (m_options.use_change_ops) {
+                        open_close_op_tag(way.visible() ? (way.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
+                    }
+
+                    write_prefix();
+                    *m_out += "<way";
+                    write_meta(way);
+
+                    if (way.tags().empty() && way.nodes().empty()) {
+                        *m_out += "/>\n";
+                        return;
+                    }
+
+                    *m_out += ">\n";
+
+                    for (const auto& node_ref : way.nodes()) {
+                        write_prefix();
+                        output_formatted("  <nd ref=\"%" PRId64 "\"/>\n", node_ref.ref());
+                    }
+
+                    write_tags(way.tags(), prefix_spaces());
+
+                    write_prefix();
+                    *m_out += "</way>\n";
+                }
+
+                void relation(const osmium::Relation& relation) {
+                    if (m_options.use_change_ops) {
+                        open_close_op_tag(relation.visible() ? (relation.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
+                    }
+
+                    write_prefix();
+                    *m_out += "<relation";
+                    write_meta(relation);
+
+                    if (relation.tags().empty() && relation.members().empty()) {
+                        *m_out += "/>\n";
+                        return;
+                    }
+
+                    *m_out += ">\n";
+
+                    for (const auto& member : relation.members()) {
+                        write_prefix();
+                        *m_out += "  <member type=\"";
+                        *m_out += item_type_to_name(member.type());
+                        output_formatted("\" ref=\"%" PRId64 "\" role=\"", member.ref());
+                        append_xml_encoded_string(*m_out, member.role());
+                        *m_out += "\"/>\n";
+                    }
+
+                    write_tags(relation.tags(), prefix_spaces());
+
+                    write_prefix();
+                    *m_out += "</relation>\n";
+                }
+
+                void changeset(const osmium::Changeset& changeset) {
+                    *m_out += " <changeset";
+
+                    output_formatted(" id=\"%" PRId32 "\"", changeset.id());
+
+                    if (changeset.created_at()) {
+                        *m_out += " created_at=\"";
+                        *m_out += changeset.created_at().to_iso();
+                        *m_out += "\"";
+                    }
+
+                    if (changeset.closed_at()) {
+                        *m_out += " closed_at=\"";
+                        *m_out += changeset.closed_at().to_iso();
+                        *m_out += "\" open=\"false\"";
+                    } else {
+                        *m_out += " open=\"true\"";
+                    }
+
+                    if (!changeset.user_is_anonymous()) {
+                        *m_out += " user=\"";
+                        append_xml_encoded_string(*m_out, changeset.user());
+                        output_formatted("\" uid=\"%d\"", changeset.uid());
+                    }
+
+                    if (changeset.bounds()) {
+                        output_formatted(" min_lat=\"%.7f\"", changeset.bounds().bottom_left().lat_without_check());
+                        output_formatted(" min_lon=\"%.7f\"", changeset.bounds().bottom_left().lon_without_check());
+                        output_formatted(" max_lat=\"%.7f\"", changeset.bounds().top_right().lat_without_check());
+                        output_formatted(" max_lon=\"%.7f\"", changeset.bounds().top_right().lon_without_check());
+                    }
+
+                    output_formatted(" num_changes=\"%" PRId32 "\"", changeset.num_changes());
+                    output_formatted(" comments_count=\"%" PRId32 "\"", changeset.num_comments());
+
+                    // If there are no tags and no comments, we can close the
+                    // tag right here and are done.
+                    if (changeset.tags().empty() && changeset.num_comments() == 0) {
+                        *m_out += "/>\n";
+                        return;
+                    }
+
+                    *m_out += ">\n";
+
+                    write_tags(changeset.tags(), 0);
+
+                    if (changeset.num_comments() > 0) {
+                        *m_out += "  <discussion>\n";
+                        write_discussion(changeset.discussion());
+                    }
+
+                    *m_out += " </changeset>\n";
+                }
+
+            }; // class XMLOutputBlock
+
+            class XMLOutputFormat : public osmium::io::detail::OutputFormat, public osmium::handler::Handler {
+
+                xml_output_options m_options;
+
+            public:
+
+                XMLOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
+                    OutputFormat(output_queue),
+                    m_options() {
+                    m_options.add_metadata     = file.is_not_false("add_metadata");
+                    m_options.use_change_ops   = file.is_true("xml_change_format");
+                    m_options.add_visible_flag = (file.has_multiple_object_versions() || file.is_true("force_visible_flag")) && !m_options.use_change_ops;
+                }
+
+                XMLOutputFormat(const XMLOutputFormat&) = delete;
+                XMLOutputFormat& operator=(const XMLOutputFormat&) = delete;
+
+                ~XMLOutputFormat() noexcept = default;
+
+                void write_header(const osmium::io::Header& header) override final {
+                    std::string out = "<?xml version='1.0' encoding='UTF-8'?>\n";
+
+                    if (m_options.use_change_ops) {
+                        out += "<osmChange version=\"0.6\" generator=\"";
+                    } else {
+                        out += "<osm version=\"0.6\"";
+
+                        std::string xml_josm_upload = header.get("xml_josm_upload");
+                        if (xml_josm_upload == "true" || xml_josm_upload == "false") {
+                            out += " upload=\"";
+                            out += xml_josm_upload;
+                            out += "\"";
+                        }
+                        out += " generator=\"";
+                    }
+                    append_xml_encoded_string(out, header.get("generator").c_str());
+                    out += "\">\n";
+
+                    for (const auto& box : header.boxes()) {
+                        out += "  <bounds";
+                        append_printf_formatted_string(out, " minlon=\"%.7f\"", box.bottom_left().lon());
+                        append_printf_formatted_string(out, " minlat=\"%.7f\"", box.bottom_left().lat());
+                        append_printf_formatted_string(out, " maxlon=\"%.7f\"", box.top_right().lon());
+                        append_printf_formatted_string(out, " maxlat=\"%.7f\"/>\n", box.top_right().lat());
+                    }
+
+                    send_to_output_queue(std::move(out));
+                }
+
+                void write_buffer(osmium::memory::Buffer&& buffer) override final {
+                    m_output_queue.push(osmium::thread::Pool::instance().submit(XMLOutputBlock{std::move(buffer), m_options}));
+                }
+
+                void write_end() override final {
+                    std::string out;
+
+                    if (m_options.use_change_ops) {
+                        out += "</osmChange>\n";
+                    } else {
+                        out += "</osm>\n";
+                    }
+
+                    send_to_output_queue(std::move(out));
+                }
+
+            }; // class XMLOutputFormat
+
+            // we want the register_output_format() function to run, setting
+            // the variable is only a side-effect, it will never be used
+            const bool registered_xml_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::xml,
+                [](const osmium::io::File& file, future_string_queue_type& output_queue) {
+                    return new osmium::io::detail::XMLOutputFormat(file, output_queue);
+            });
+
+            // dummy function to silence the unused variable warning from above
+            inline bool get_registered_xml_output() noexcept {
+                return registered_xml_output;
+            }
+
+        } // namespace detail
+
+    } // namespace output
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_XML_OUTPUT_FORMAT_HPP
diff --git a/contrib/libosmium/osmium/io/detail/zlib.hpp b/contrib/libosmium/osmium/io/detail/zlib.hpp
new file mode 100644
index 0000000..4d86168
--- /dev/null
+++ b/contrib/libosmium/osmium/io/detail/zlib.hpp
@@ -0,0 +1,115 @@
+#ifndef OSMIUM_IO_DETAIL_ZLIB_HPP
+#define OSMIUM_IO_DETAIL_ZLIB_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <memory>
+#include <stdexcept>
+#include <string>
+
+#include <zlib.h>
+
+#include <osmium/io/error.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        namespace detail {
+
+            /**
+             * Compress data using zlib.
+             *
+             * Note that this function can not compress data larger than
+             * what fits in an unsigned long, on Windows this is usually 32bit.
+             *
+             * @param input Data to compress.
+             * @returns Compressed data.
+             */
+            inline std::string zlib_compress(const std::string& input) {
+                unsigned long output_size = ::compressBound(osmium::static_cast_with_assert<unsigned long>(input.size()));
+
+                std::string output(output_size, '\0');
+
+                auto result = ::compress(
+                    reinterpret_cast<unsigned char*>(const_cast<char *>(output.data())),
+                    &output_size,
+                    reinterpret_cast<const unsigned char*>(input.data()),
+                    osmium::static_cast_with_assert<unsigned long>(input.size())
+                );
+
+                if (result != Z_OK) {
+                    throw io_error(std::string("failed to compress data: ") + zError(result));
+                }
+
+                output.resize(output_size);
+
+                return output;
+            }
+
+            /**
+             * Uncompress data using zlib.
+             *
+             * Note that this function can not uncompress data larger than
+             * what fits in an unsigned long, on Windows this is usually 32bit.
+             *
+             * @param input Compressed input data.
+             * @param raw_size Size of uncompressed data.
+             * @param output Uncompressed result data.
+             * @returns Pointer and size to incompressed data.
+             */
+            inline std::pair<const char*, size_t> zlib_uncompress_string(const char* input, unsigned long input_size, unsigned long raw_size, std::string& output) {
+                output.resize(raw_size);
+
+                auto result = ::uncompress(
+                    reinterpret_cast<unsigned char*>(&*output.begin()),
+                    &raw_size,
+                    reinterpret_cast<const unsigned char*>(input),
+                    input_size
+                );
+
+                if (result != Z_OK) {
+                    throw io_error(std::string("failed to uncompress data: ") + zError(result));
+                }
+
+                return std::make_pair(output.data(), output.size());
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_ZLIB_HPP
diff --git a/contrib/libosmium/osmium/io/error.hpp b/contrib/libosmium/osmium/io/error.hpp
new file mode 100644
index 0000000..0b5393f
--- /dev/null
+++ b/contrib/libosmium/osmium/io/error.hpp
@@ -0,0 +1,70 @@
+#ifndef OSMIUM_IO_ERROR_HPP
+#define OSMIUM_IO_ERROR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <stdexcept>
+#include <string>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when some kind of input/output operation failed.
+     */
+    struct io_error : public std::runtime_error {
+
+        io_error(const std::string& what) :
+            std::runtime_error(what) {
+        }
+
+        io_error(const char* what) :
+            std::runtime_error(what) {
+        }
+
+    }; // struct io_error
+
+    struct unsupported_file_format_error : public io_error {
+
+        unsupported_file_format_error(const std::string& what) :
+            io_error(what) {
+        }
+
+        unsupported_file_format_error(const char* what) :
+            io_error(what) {
+        }
+
+    }; // struct unsupported_file_format_error
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_ERROR_HPP
diff --git a/contrib/libosmium/osmium/io/file.hpp b/contrib/libosmium/osmium/io/file.hpp
new file mode 100644
index 0000000..87fcc37
--- /dev/null
+++ b/contrib/libosmium/osmium/io/file.hpp
@@ -0,0 +1,328 @@
+#ifndef OSMIUM_IO_FILE_HPP
+#define OSMIUM_IO_FILE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <stdexcept>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <osmium/io/error.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/file_compression.hpp>
+#include <osmium/util/options.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Everything related to input and output of OSM data.
+     */
+    namespace io {
+
+        namespace detail {
+
+            inline std::vector<std::string> split(const std::string& in, const char delim) {
+                std::vector<std::string> result;
+                std::stringstream ss(in);
+                std::string item;
+                while (std::getline(ss, item, delim)) {
+                    result.push_back(item);
+                }
+                return result;
+            }
+
+        } // namespace detail
+
+        /**
+         * This class describes an OSM file in one of several different formats.
+         *
+         * If the filename is empty or "-", this means stdin or stdout is used.
+         */
+        class File : public osmium::util::Options {
+
+        private:
+
+            std::string m_filename;
+
+            const char* m_buffer;
+            size_t m_buffer_size;
+
+            std::string m_format_string;
+
+            file_format m_file_format {file_format::unknown};
+
+            file_compression m_file_compression {file_compression::none};
+
+            bool m_has_multiple_object_versions {false};
+
+        public:
+
+            /**
+             * Create File using type and encoding from filename or given
+             * format specification.
+             *
+             * @param filename Filename including suffix. The type and encoding
+             *                 of the file will be taken from the suffix.
+             *                 An empty filename or "-" means stdin or stdout.
+             * @param format File format as string. See the description of the
+             *               parse_format() function for details. If this is
+             *               empty the format will be deduced from the suffix
+             *               of the filename.
+             */
+            explicit File(const std::string& filename = "", const std::string& format = "") :
+                Options(),
+                m_filename(filename),
+                m_buffer(nullptr),
+                m_buffer_size(0),
+                m_format_string(format) {
+
+                // stdin/stdout
+                if (m_filename == "-") {
+                    m_filename = "";
+                }
+
+                // if filename is a URL, default to XML format
+                std::string protocol = m_filename.substr(0, m_filename.find_first_of(':'));
+                if (protocol == "http" || protocol == "https") {
+                    m_file_format = file_format::xml;
+                }
+
+                if (format.empty()) {
+                    detect_format_from_suffix(m_filename);
+                } else {
+                    parse_format(format);
+                }
+            }
+
+            /**
+             * Create File using buffer pointer and size and type and encoding
+             * from given format specification.
+             *
+             * @param buffer Pointer to buffer with data.
+             * @param size   Size of buffer.
+             * @param format File format as string. See the description of the
+             *               parse_format() function for details.
+             */
+            explicit File(const char* buffer, size_t size, const std::string& format = "") :
+                Options(),
+                m_filename(),
+                m_buffer(buffer),
+                m_buffer_size(size),
+                m_format_string(format) {
+                if (format != "") {
+                    parse_format(format);
+                }
+            }
+
+            File(const File&) = default;
+            File& operator=(const File&) = default;
+
+            File(File&&) = default;
+            File& operator=(File&&) = default;
+
+            ~File() = default;
+
+            const char* buffer() const noexcept {
+                return m_buffer;
+            }
+
+            size_t buffer_size() const noexcept {
+                return m_buffer_size;
+            }
+
+            void parse_format(const std::string& format) {
+                std::vector<std::string> options = detail::split(format, ',');
+
+                // if the first item in the format list doesn't contain
+                // an equals sign, it is a format
+                if (!options.empty() && options[0].find_first_of('=') == std::string::npos) {
+                    detect_format_from_suffix(options[0]);
+                    options.erase(options.begin());
+                }
+
+                for (auto& option : options) {
+                    size_t pos = option.find_first_of('=');
+                    if (pos == std::string::npos) {
+                        set(option, true);
+                    } else {
+                        std::string value = option.substr(pos+1);
+                        option.erase(pos);
+                        set(option, value);
+                    }
+                }
+
+                if (get("history") == "true") {
+                    m_has_multiple_object_versions = true;
+                } else if (get("history") == "false") {
+                    m_has_multiple_object_versions = false;
+                }
+            }
+
+            void detect_format_from_suffix(const std::string& name) {
+                std::vector<std::string> suffixes = detail::split(name, '.');
+
+                if (suffixes.empty()) return;
+
+                // if the last suffix is one of a known set of compressions,
+                // set that compression
+                if (suffixes.back() == "gz") {
+                    m_file_compression = file_compression::gzip;
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "bz2") {
+                    m_file_compression = file_compression::bzip2;
+                    suffixes.pop_back();
+                }
+
+                if (suffixes.empty()) return;
+
+                // if the last suffix is one of a known set of formats,
+                // set that format
+                if (suffixes.back() == "pbf") {
+                    m_file_format = file_format::pbf;
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "xml") {
+                    m_file_format = file_format::xml;
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "opl") {
+                    m_file_format = file_format::opl;
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "json") {
+                    m_file_format = file_format::json;
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "o5m") {
+                    m_file_format = file_format::o5m;
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "o5c") {
+                    m_file_format = file_format::o5m;
+                    m_has_multiple_object_versions = true;
+                    set("o5c_change_format", true);
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "debug") {
+                    m_file_format = file_format::debug;
+                    suffixes.pop_back();
+                }
+
+                if (suffixes.empty()) return;
+
+                if (suffixes.back() == "osm") {
+                    if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "osh") {
+                    if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
+                    m_has_multiple_object_versions = true;
+                    suffixes.pop_back();
+                } else if (suffixes.back() == "osc") {
+                    if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
+                    m_has_multiple_object_versions = true;
+                    set("xml_change_format", true);
+                    suffixes.pop_back();
+                }
+            }
+
+            /**
+             * Check file format etc. for consistency and throw exception if
+             * there is a problem.
+             *
+             * @throws osmium::io_error
+             */
+            const File& check() const {
+                if (m_file_format == file_format::unknown) {
+                    std::string msg = "Could not detect file format";
+                    if (!m_format_string.empty())  {
+                        msg += " from format string '";
+                        msg += m_format_string;
+                        msg += "'";
+                    }
+                    if (m_filename.empty()) {
+                        msg += " for stdin/stdout";
+                    } else {
+                        msg += " for filename '";
+                        msg += m_filename;
+                        msg += "'";
+                    }
+                    msg += ".";
+                    throw io_error(msg);
+                }
+                return *this;
+            }
+
+            file_format format() const noexcept {
+                return m_file_format;
+            }
+
+            File& set_format(file_format format) noexcept {
+                m_file_format = format;
+                return *this;
+            }
+
+            file_compression compression() const noexcept {
+                return m_file_compression;
+            }
+
+            File& set_compression(file_compression compression) noexcept {
+                m_file_compression = compression;
+                return *this;
+            }
+
+            bool has_multiple_object_versions() const noexcept {
+                return m_has_multiple_object_versions;
+            }
+
+            File& set_has_multiple_object_versions(bool value) noexcept {
+                m_has_multiple_object_versions = value;
+                return *this;
+            }
+
+            File& filename(const std::string& filename) {
+                if (filename == "-") {
+                    m_filename = "";
+                } else {
+                    m_filename = filename;
+                }
+                return *this;
+            }
+
+            const std::string& filename() const noexcept {
+                return m_filename;
+            }
+
+        }; // class File
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_FILE_HPP
diff --git a/contrib/libosmium/osmium/io/file_compression.hpp b/contrib/libosmium/osmium/io/file_compression.hpp
new file mode 100644
index 0000000..292ddcf
--- /dev/null
+++ b/contrib/libosmium/osmium/io/file_compression.hpp
@@ -0,0 +1,72 @@
+#ifndef OSMIUM_IO_FILE_COMPRESSION_HPP
+#define OSMIUM_IO_FILE_COMPRESSION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iosfwd>
+
+namespace osmium {
+
+    namespace io {
+
+        enum class file_compression {
+            none  = 0,
+            gzip  = 1,
+            bzip2 = 2
+        };
+
+// avoid g++ false positive
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+        inline const char* as_string(file_compression compression) {
+            switch (compression) {
+                case file_compression::none:
+                    return "none";
+                case file_compression::gzip:
+                    return "gzip";
+                case file_compression::bzip2:
+                    return "bzip2";
+            }
+        }
+#pragma GCC diagnostic pop
+
+        template <typename TChar, typename TTraits>
+        inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const file_compression compression) {
+            return out << as_string(compression);
+        }
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_FILE_COMPRESSION_HPP
diff --git a/contrib/libosmium/osmium/io/file_format.hpp b/contrib/libosmium/osmium/io/file_format.hpp
new file mode 100644
index 0000000..edfb1ff
--- /dev/null
+++ b/contrib/libosmium/osmium/io/file_format.hpp
@@ -0,0 +1,84 @@
+#ifndef OSMIUM_IO_FILE_FORMAT_HPP
+#define OSMIUM_IO_FILE_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iosfwd>
+
+namespace osmium {
+
+    namespace io {
+
+        enum class file_format {
+            unknown = 0,
+            xml     = 1,
+            pbf     = 2,
+            opl     = 3,
+            json    = 4,
+            o5m     = 5,
+            debug   = 6
+        };
+
+// avoid g++ false positive
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+        inline const char* as_string(file_format format) {
+            switch (format) {
+                case file_format::unknown:
+                    return "unknown";
+                case file_format::xml:
+                    return "XML";
+                case file_format::pbf:
+                    return "PBF";
+                case file_format::opl:
+                    return "OPL";
+                case file_format::json:
+                    return "JSON";
+                case file_format::o5m:
+                    return "O5M";
+                case file_format::debug:
+                    return "DEBUG";
+            }
+        }
+#pragma GCC diagnostic pop
+
+        template <typename TChar, typename TTraits>
+        inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const file_format format) {
+            return out << as_string(format);
+        }
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_FILE_FORMAT_HPP
diff --git a/contrib/libosmium/osmium/io/gzip_compression.hpp b/contrib/libosmium/osmium/io/gzip_compression.hpp
new file mode 100644
index 0000000..705f416
--- /dev/null
+++ b/contrib/libosmium/osmium/io/gzip_compression.hpp
@@ -0,0 +1,277 @@
+#ifndef OSMIUM_IO_GZIP_COMPRESSION_HPP
+#define OSMIUM_IO_GZIP_COMPRESSION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * Include this file if you want to read or write gzip-compressed OSM XML
+ * files.
+ *
+ * @attention If you include this file, you'll need to link with `libz`.
+ */
+
+#include <stdexcept>
+#include <string>
+
+#include <errno.h>
+#include <zlib.h>
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/error.hpp>
+#include <osmium/io/file_compression.hpp>
+#include <osmium/io/writer_options.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception thrown when there are problems compressing or
+     * decompressing gzip files.
+     */
+    struct gzip_error : public io_error {
+
+        int gzip_error_code;
+        int system_errno;
+
+        gzip_error(const std::string& what, int error_code) :
+            io_error(what),
+            gzip_error_code(error_code),
+            system_errno(error_code == Z_ERRNO ? errno : 0) {
+        }
+
+    }; // struct gzip_error
+
+    namespace io {
+
+        namespace detail {
+
+            OSMIUM_NORETURN inline void throw_gzip_error(gzFile gzfile, const char* msg, int zlib_error = 0) {
+                std::string error("gzip error: ");
+                error += msg;
+                error += ": ";
+                int errnum = zlib_error;
+                if (zlib_error) {
+                    error += std::to_string(zlib_error);
+                } else {
+                    error += ::gzerror(gzfile, &errnum);
+                }
+                throw osmium::gzip_error(error, errnum);
+            }
+
+        } // namespace detail
+
+        class GzipCompressor : public Compressor {
+
+            int m_fd;
+            gzFile m_gzfile;
+
+        public:
+
+            explicit GzipCompressor(int fd, fsync sync) :
+                Compressor(sync),
+                m_fd(dup(fd)),
+                m_gzfile(::gzdopen(fd, "w")) {
+                if (!m_gzfile) {
+                    detail::throw_gzip_error(m_gzfile, "write initialization failed");
+                }
+            }
+
+            ~GzipCompressor() noexcept override final {
+                try {
+                    close();
+                } catch (...) {
+                    // Ignore any exceptions because destructor must not throw.
+                }
+            }
+
+            void write(const std::string& data) override final {
+                if (!data.empty()) {
+                    int nwrite = ::gzwrite(m_gzfile, data.data(), static_cast_with_assert<unsigned int>(data.size()));
+                    if (nwrite == 0) {
+                        detail::throw_gzip_error(m_gzfile, "write failed");
+                    }
+                }
+            }
+
+            void close() override final {
+                if (m_gzfile) {
+                    int result = ::gzclose(m_gzfile);
+                    m_gzfile = nullptr;
+                    if (result != Z_OK) {
+                        detail::throw_gzip_error(m_gzfile, "write close failed", result);
+                    }
+                    if (do_fsync()) {
+                        osmium::io::detail::reliable_fsync(m_fd);
+                    }
+                    osmium::io::detail::reliable_close(m_fd);
+                }
+            }
+
+        }; // class GzipCompressor
+
+        class GzipDecompressor : public Decompressor {
+
+            gzFile m_gzfile;
+
+        public:
+
+            explicit GzipDecompressor(int fd) :
+                Decompressor(),
+                m_gzfile(::gzdopen(fd, "r")) {
+                if (!m_gzfile) {
+                    detail::throw_gzip_error(m_gzfile, "read initialization failed");
+                }
+            }
+
+            ~GzipDecompressor() noexcept override final {
+                try {
+                    close();
+                } catch (...) {
+                    // Ignore any exceptions because destructor must not throw.
+                }
+            }
+
+            std::string read() override final {
+                std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
+                int nread = ::gzread(m_gzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<unsigned int>(buffer.size()));
+                if (nread < 0) {
+                    detail::throw_gzip_error(m_gzfile, "read failed");
+                }
+                buffer.resize(static_cast<std::string::size_type>(nread));
+                return buffer;
+            }
+
+            void close() override final {
+                if (m_gzfile) {
+                    int result = ::gzclose(m_gzfile);
+                    m_gzfile = nullptr;
+                    if (result != Z_OK) {
+                        detail::throw_gzip_error(m_gzfile, "read close failed", result);
+                    }
+                }
+            }
+
+        }; // class GzipDecompressor
+
+        class GzipBufferDecompressor : public Decompressor {
+
+            const char* m_buffer;
+            size_t m_buffer_size;
+            z_stream m_zstream;
+
+        public:
+
+            GzipBufferDecompressor(const char* buffer, size_t size) :
+                m_buffer(buffer),
+                m_buffer_size(size),
+                m_zstream() {
+                m_zstream.next_in = reinterpret_cast<unsigned char*>(const_cast<char*>(buffer));
+                m_zstream.avail_in = static_cast_with_assert<unsigned int>(size);
+                int result = inflateInit2(&m_zstream, MAX_WBITS | 32);
+                if (result != Z_OK) {
+                    std::string message("gzip error: decompression init failed: ");
+                    if (m_zstream.msg) {
+                        message.append(m_zstream.msg);
+                    }
+                    throw osmium::gzip_error(message, result);
+                }
+            }
+
+            ~GzipBufferDecompressor() noexcept override final {
+                try {
+                    close();
+                } catch (...) {
+                    // Ignore any exceptions because destructor must not throw.
+                }
+            }
+
+            std::string read() override final {
+                std::string output;
+
+                if (m_buffer) {
+                    const size_t buffer_size = 10240;
+                    output.append(buffer_size, '\0');
+                    m_zstream.next_out = reinterpret_cast<unsigned char*>(const_cast<char*>(output.data()));
+                    m_zstream.avail_out = buffer_size;
+                    int result = inflate(&m_zstream, Z_SYNC_FLUSH);
+
+                    if (result != Z_OK) {
+                        m_buffer = nullptr;
+                        m_buffer_size = 0;
+                    }
+
+                    if (result != Z_OK && result != Z_STREAM_END) {
+                        std::string message("gzip error: inflate failed: ");
+                        if (m_zstream.msg) {
+                            message.append(m_zstream.msg);
+                        }
+                        throw osmium::gzip_error(message, result);
+                    }
+
+                    output.resize(static_cast<unsigned long>(m_zstream.next_out - reinterpret_cast<const unsigned char*>(output.data())));
+                }
+
+                return output;
+            }
+
+            void close() override final {
+                inflateEnd(&m_zstream);
+            }
+
+        }; // class GzipBufferDecompressor
+
+        namespace detail {
+
+            // we want the register_compression() function to run, setting
+            // the variable is only a side-effect, it will never be used
+            const bool registered_gzip_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::gzip,
+                [](int fd, fsync sync) { return new osmium::io::GzipCompressor(fd, sync); },
+                [](int fd) { return new osmium::io::GzipDecompressor(fd); },
+                [](const char* buffer, size_t size) { return new osmium::io::GzipBufferDecompressor(buffer, size); }
+            );
+
+            // dummy function to silence the unused variable warning from above
+            inline bool get_registered_gzip_compression() noexcept {
+                return registered_gzip_compression;
+            }
+
+        } // namespace detail
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_GZIP_COMPRESSION_HPP
diff --git a/contrib/libosmium/osmium/io/header.hpp b/contrib/libosmium/osmium/io/header.hpp
new file mode 100644
index 0000000..4b0830a
--- /dev/null
+++ b/contrib/libosmium/osmium/io/header.hpp
@@ -0,0 +1,122 @@
+#ifndef OSMIUM_IO_HEADER_HPP
+#define OSMIUM_IO_HEADER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <initializer_list>
+#include <vector>
+
+#include <osmium/osm/box.hpp>
+#include <osmium/util/options.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        /**
+        * Meta information from the header of an OSM file.
+        */
+        class Header : public osmium::util::Options {
+
+            /// Bounding boxes
+            std::vector<osmium::Box> m_boxes;
+
+            /**
+            * Are there possibly multiple versions of the same object in this stream of objects?
+            * This is true for history files and for change files, but not for normal OSM files.
+            */
+            bool m_has_multiple_object_versions = false;
+
+        public:
+
+            Header() = default;
+
+            explicit Header(const std::initializer_list<osmium::util::Options::value_type>& values) :
+                Options(values) {
+            }
+
+            Header(const Header&) = default;
+            Header& operator=(const Header&) = default;
+
+            Header(Header&&) = default;
+            Header& operator=(Header&&) = default;
+
+            ~Header() = default;
+
+            std::vector<osmium::Box>& boxes() noexcept {
+                return m_boxes;
+            }
+
+            const std::vector<osmium::Box>& boxes() const noexcept {
+                return m_boxes;
+            }
+
+            Header& boxes(const std::vector<osmium::Box>& boxes) noexcept {
+                m_boxes = boxes;
+                return *this;
+            }
+
+            osmium::Box box() const {
+                return m_boxes.empty() ? osmium::Box() : m_boxes.front();
+            }
+
+            osmium::Box joined_boxes() const {
+                osmium::Box box;
+                for (const auto& b : m_boxes) {
+                    box.extend(b.bottom_left());
+                    box.extend(b.top_right());
+                }
+                return box;
+            }
+
+            Header& add_box(const osmium::Box& box) {
+                m_boxes.push_back(box);
+                return *this;
+            }
+
+            bool has_multiple_object_versions() const noexcept {
+                return m_has_multiple_object_versions;
+            }
+
+            Header& set_has_multiple_object_versions(bool value) noexcept {
+                m_has_multiple_object_versions = value;
+                return *this;
+            }
+
+        }; // class Header
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_HEADER_HPP
diff --git a/contrib/libosmium/osmium/io/input_iterator.hpp b/contrib/libosmium/osmium/io/input_iterator.hpp
new file mode 100644
index 0000000..8647763
--- /dev/null
+++ b/contrib/libosmium/osmium/io/input_iterator.hpp
@@ -0,0 +1,178 @@
+#ifndef OSMIUM_IO_INPUT_ITERATOR_HPP
+#define OSMIUM_IO_INPUT_ITERATOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        /**
+         * This iterator class allows you to iterate over all items from a
+         * source. It hides all the buffer handling and makes the contents of a
+         * source accessible as a normal STL input iterator.
+         */
+        template <typename TSource, typename TItem = osmium::memory::Item>
+        class InputIterator {
+
+            static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "TItem must derive from osmium::buffer::Item");
+
+            typedef typename osmium::memory::Buffer::t_iterator<TItem> item_iterator;
+
+            TSource* m_source;
+            std::shared_ptr<osmium::memory::Buffer> m_buffer;
+            item_iterator m_iter {};
+
+            void update_buffer() {
+                do {
+                    m_buffer = std::make_shared<osmium::memory::Buffer>(std::move(m_source->read()));
+                    if (!m_buffer || !*m_buffer) { // end of input
+                        m_source = nullptr;
+                        m_buffer.reset();
+                        m_iter = item_iterator();
+                        return;
+                    }
+                    m_iter = m_buffer->begin<TItem>();
+                } while (m_iter == m_buffer->end<TItem>());
+            }
+
+        public:
+
+            typedef std::input_iterator_tag iterator_category;
+            typedef TItem                   value_type;
+            typedef ptrdiff_t               difference_type;
+            typedef TItem*                  pointer;
+            typedef TItem&                  reference;
+
+            explicit InputIterator(TSource& source) :
+                m_source(&source) {
+                update_buffer();
+            }
+
+            // end iterator
+            InputIterator() noexcept :
+                m_source(nullptr) {
+            }
+
+            InputIterator& operator++() {
+                assert(m_source);
+                assert(m_buffer);
+                assert(m_iter);
+                ++m_iter;
+                if (m_iter == m_buffer->end<TItem>()) {
+                    update_buffer();
+                }
+                return *this;
+            }
+
+            InputIterator operator++(int) {
+                InputIterator tmp(*this);
+                operator++();
+                return tmp;
+            }
+
+            bool operator==(const InputIterator& rhs) const noexcept {
+                return m_source == rhs.m_source &&
+                       m_buffer == rhs.m_buffer &&
+                       m_iter == rhs.m_iter;
+            }
+
+            bool operator!=(const InputIterator& rhs) const noexcept {
+                return !(*this == rhs);
+            }
+
+            reference operator*() const {
+                assert(m_iter);
+                return static_cast<reference>(*m_iter);
+            }
+
+            pointer operator->() const {
+                assert(m_iter);
+                return &static_cast<reference>(*m_iter);
+            }
+
+        }; // class InputIterator
+
+        template <typename TSource, typename TItem = osmium::memory::Item>
+        class InputIteratorRange {
+
+            InputIterator<TSource, TItem> m_begin;
+            InputIterator<TSource, TItem> m_end;
+
+        public:
+
+            InputIteratorRange(InputIterator<TSource, TItem>&& begin,
+                               InputIterator<TSource, TItem>&& end) :
+                m_begin(std::move(begin)),
+                m_end(std::move(end)) {
+            }
+
+            InputIterator<TSource, TItem> begin() const noexcept {
+                return m_begin;
+            }
+
+            InputIterator<TSource, TItem> end() const noexcept {
+                return m_end;
+            }
+
+            const InputIterator<TSource, TItem> cbegin() const noexcept {
+                return m_begin;
+            }
+
+            const InputIterator<TSource, TItem> cend() const noexcept {
+                return m_end;
+            }
+
+        }; // class InputIteratorRange
+
+        template <typename TItem, typename TSource>
+        InputIteratorRange<TSource, TItem> make_input_iterator_range(TSource& source) {
+            using it_type = InputIterator<TSource, TItem>;
+            return InputIteratorRange<TSource, TItem>(it_type{source}, it_type{});
+        }
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_INPUT_ITERATOR_HPP
diff --git a/contrib/libosmium/osmium/io/o5m_input.hpp b/contrib/libosmium/osmium/io/o5m_input.hpp
new file mode 100644
index 0000000..b63f728
--- /dev/null
+++ b/contrib/libosmium/osmium/io/o5m_input.hpp
@@ -0,0 +1,45 @@
+#ifndef OSMIUM_IO_O5M_INPUT_HPP
+#define OSMIUM_IO_O5M_INPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * Include this file if you want to read OSM o5m and o5c files.
+ */
+
+#include <osmium/io/reader.hpp> // IWYU pragma: export
+#include <osmium/io/detail/o5m_input_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_O5M_INPUT_HPP
diff --git a/contrib/libosmium/osmium/io/opl_output.hpp b/contrib/libosmium/osmium/io/opl_output.hpp
new file mode 100644
index 0000000..04385d9
--- /dev/null
+++ b/contrib/libosmium/osmium/io/opl_output.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_OPL_OUTPUT_HPP
+#define OSMIUM_IO_OPL_OUTPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/io/writer.hpp> // IWYU pragma: export
+#include <osmium/io/detail/opl_output_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_OPL_OUTPUT_HPP
diff --git a/contrib/libosmium/osmium/io/output_iterator.hpp b/contrib/libosmium/osmium/io/output_iterator.hpp
new file mode 100644
index 0000000..3d60fe6
--- /dev/null
+++ b/contrib/libosmium/osmium/io/output_iterator.hpp
@@ -0,0 +1,133 @@
+#ifndef OSMIUM_IO_OUTPUT_ITERATOR_HPP
+#define OSMIUM_IO_OUTPUT_ITERATOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <utility>
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/diff_object.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    namespace memory {
+        class Item;
+    } // namespace memory
+
+    namespace io {
+
+        template <typename TDest>
+        class OutputIterator : public std::iterator<std::output_iterator_tag, osmium::memory::Item> {
+
+            TDest* m_destination;
+
+        public:
+
+            explicit OutputIterator(TDest& destination) :
+                m_destination(&destination) {
+            }
+
+            /**
+             * Warning! Use of buffer size argument on OutputIterator
+             * constructor is deprecated. Call Writer::set_buffer_size()
+             * instead if you want to change the default.
+             */
+            OSMIUM_DEPRECATED OutputIterator(TDest& destination, const size_t buffer_size) :
+                m_destination(&destination) {
+                destination.set_buffer_size(buffer_size);
+            }
+
+            OutputIterator(const OutputIterator&) = default;
+            OutputIterator(OutputIterator&&) = default;
+
+            OutputIterator& operator=(const OutputIterator&) = default;
+            OutputIterator& operator=(OutputIterator&&) = default;
+
+            ~OutputIterator() = default;
+
+            /**
+             * Warning! Calling OutputIterator<Writer>::flush() is usually not
+             * needed any more. Call flush() on the Writer instead if needed.
+             */
+            OSMIUM_DEPRECATED void flush() {
+                m_destination->flush();
+            }
+
+            OutputIterator& operator=(const osmium::memory::Item& item) {
+                (*m_destination)(item);
+                return *this;
+            }
+
+            OutputIterator& operator=(const osmium::DiffObject& diff) {
+                return this->operator=(diff.curr());
+            }
+
+            OutputIterator& operator*() {
+                return *this;
+            }
+
+            OutputIterator& operator++() {
+                return *this;
+            }
+
+            OutputIterator& operator++(int) {
+                return *this;
+            }
+
+        }; // class OutputIterator
+
+        template <typename TDest>
+        OutputIterator<TDest> make_output_iterator(TDest& destination) {
+            return OutputIterator<TDest>{destination};
+        }
+
+        /**
+         * Warning! Use of buffer size argument on make_output_iterator is
+         * deprecated. Call Writer::set_buffer_size() instead if you want to
+         * change the default.
+         */
+        template <typename TDest>
+        OSMIUM_DEPRECATED OutputIterator<TDest> make_output_iterator(TDest& destination, const size_t buffer_size) {
+            destination.set_buffer_size(buffer_size);
+            return OutputIterator<TDest>{destination};
+        }
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_OUTPUT_ITERATOR_HPP
diff --git a/contrib/libosmium/osmium/io/overwrite.hpp b/contrib/libosmium/osmium/io/overwrite.hpp
new file mode 100644
index 0000000..f9fbc71
--- /dev/null
+++ b/contrib/libosmium/osmium/io/overwrite.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_OVERWRITE_HPP
+#define OSMIUM_IO_OVERWRITE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#pragma message("Including overwrite.hpp is deprecated, #include <osmium/io/writer_options.hpp> instead.")
+#include <osmium/io/writer_options.hpp>
+
+#endif // OSMIUM_IO_OVERWRITE_HPP
diff --git a/contrib/libosmium/osmium/io/pbf_input.hpp b/contrib/libosmium/osmium/io/pbf_input.hpp
new file mode 100644
index 0000000..d7f3787
--- /dev/null
+++ b/contrib/libosmium/osmium/io/pbf_input.hpp
@@ -0,0 +1,48 @@
+#ifndef OSMIUM_IO_PBF_INPUT_HPP
+#define OSMIUM_IO_PBF_INPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * Include this file if you want to read OSM PBF files.
+ *
+ * @attention If you include this file, you'll need to link with
+ *            `libz`, and enable multithreading.
+ */
+
+#include <osmium/io/reader.hpp> // IWYU pragma: export
+#include <osmium/io/detail/pbf_input_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_PBF_INPUT_HPP
diff --git a/contrib/libosmium/osmium/io/pbf_output.hpp b/contrib/libosmium/osmium/io/pbf_output.hpp
new file mode 100644
index 0000000..dad1013
--- /dev/null
+++ b/contrib/libosmium/osmium/io/pbf_output.hpp
@@ -0,0 +1,48 @@
+#ifndef OSMIUM_IO_PBF_OUTPUT_HPP
+#define OSMIUM_IO_PBF_OUTPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * Include this file if you want to write OSM PBF files.
+ *
+ * @attention If you include this file, you'll need to link with
+ *            `libz`, and enable multithreading.
+ */
+
+#include <osmium/io/writer.hpp> // IWYU pragma: export
+#include <osmium/io/detail/pbf_output_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_PBF_OUTPUT_HPP
diff --git a/contrib/libosmium/osmium/io/reader.hpp b/contrib/libosmium/osmium/io/reader.hpp
new file mode 100644
index 0000000..54c518e
--- /dev/null
+++ b/contrib/libosmium/osmium/io/reader.hpp
@@ -0,0 +1,380 @@
+#ifndef OSMIUM_IO_READER_HPP
+#define OSMIUM_IO_READER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cerrno>
+#include <cstdlib>
+#include <fcntl.h>
+#include <future>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <thread>
+#include <utility>
+
+#ifndef _WIN32
+# include <sys/wait.h>
+#endif
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/detail/input_format.hpp>
+#include <osmium/io/detail/read_thread.hpp>
+#include <osmium/io/detail/read_write.hpp>
+#include <osmium/io/detail/queue_util.hpp>
+#include <osmium/io/error.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/thread/util.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        /**
+         * This is the user-facing interface for reading OSM files. Instantiate
+         * an object of this class with a file name or osmium::io::File object
+         * and then call read() on it in a loop until it returns an invalid
+         * Buffer.
+         */
+        class Reader {
+
+            static constexpr size_t max_input_queue_size = 20; // XXX
+            static constexpr size_t max_osmdata_queue_size = 20; // XXX
+
+            osmium::io::File m_file;
+            osmium::osm_entity_bits::type m_read_which_entities;
+
+            enum class status {
+                okay   = 0, // normal reading
+                error  = 1, // some error occurred while reading
+                closed = 2, // close() called successfully after eof
+                eof    = 3  // eof of file was reached without error
+            } m_status;
+
+            int m_childpid;
+
+            detail::future_string_queue_type m_input_queue;
+
+            std::unique_ptr<osmium::io::Decompressor> m_decompressor;
+
+            osmium::io::detail::ReadThreadManager m_read_thread_manager;
+
+            detail::future_buffer_queue_type m_osmdata_queue;
+            detail::queue_wrapper<osmium::memory::Buffer> m_osmdata_queue_wrapper;
+
+            std::future<osmium::io::Header> m_header_future;
+            osmium::io::Header m_header;
+
+            osmium::thread::thread_handler m_thread;
+
+            // This function will run in a separate thread.
+            static void parser_thread(const osmium::io::File& file,
+                                      detail::future_string_queue_type& input_queue,
+                                      detail::future_buffer_queue_type& osmdata_queue,
+                                      std::promise<osmium::io::Header>&& header_promise,
+                                      osmium::osm_entity_bits::type read_which_entities) {
+                std::promise<osmium::io::Header> promise = std::move(header_promise);
+                auto creator = detail::ParserFactory::instance().get_creator_function(file);
+                auto parser = creator(input_queue, osmdata_queue, promise, read_which_entities);
+                parser->parse();
+            }
+
+#ifndef _WIN32
+            /**
+             * Fork and execute the given command in the child.
+             * A pipe is created between the child and the parent.
+             * The child writes to the pipe, the parent reads from it.
+             * This function never returns in the child.
+             *
+             * @param command Command to execute in the child.
+             * @param filename Filename to give to command as argument.
+             * @returns File descriptor of pipe in the parent.
+             * @throws std::system_error if a system call fails.
+             */
+            static int execute(const std::string& command, const std::string& filename, int* childpid) {
+                int pipefd[2];
+                if (pipe(pipefd) < 0) {
+                    throw std::system_error(errno, std::system_category(), "opening pipe failed");
+                }
+                pid_t pid = fork();
+                if (pid < 0) {
+                    throw std::system_error(errno, std::system_category(), "fork failed");
+                }
+                if (pid == 0) { // child
+                    // close all file descriptors except one end of the pipe
+                    for (int i = 0; i < 32; ++i) {
+                        if (i != pipefd[1]) {
+                            ::close(i);
+                        }
+                    }
+                    if (dup2(pipefd[1], 1) < 0) { // put end of pipe as stdout/stdin
+                        exit(1);
+                    }
+
+                    ::open("/dev/null", O_RDONLY); // stdin
+                    ::open("/dev/null", O_WRONLY); // stderr
+                    // hack: -g switches off globbing in curl which allows [] to be used in file names
+                    // this is important for XAPI URLs
+                    // in theory this execute() function could be used for other commands, but it is
+                    // only used for curl at the moment, so this is okay.
+                    if (::execlp(command.c_str(), command.c_str(), "-g", filename.c_str(), nullptr) < 0) {
+                        exit(1);
+                    }
+                }
+                // parent
+                *childpid = pid;
+                ::close(pipefd[1]);
+                return pipefd[0];
+            }
+#endif
+
+            /**
+             * Open File for reading. Handles URLs or normal files. URLs
+             * are opened by executing the "curl" program (which must be installed)
+             * and reading from its output.
+             *
+             * @returns File descriptor of open file or pipe.
+             * @throws std::system_error if a system call fails.
+             */
+            static int open_input_file_or_url(const std::string& filename, int* childpid) {
+                std::string protocol = filename.substr(0, filename.find_first_of(':'));
+                if (protocol == "http" || protocol == "https" || protocol == "ftp" || protocol == "file") {
+#ifndef _WIN32
+                    return execute("curl", filename, childpid);
+#else
+                    throw io_error("Reading OSM files from the network currently not supported on Windows.");
+#endif
+                } else {
+                    return osmium::io::detail::open_for_reading(filename);
+                }
+            }
+
+        public:
+
+            /**
+             * Create new Reader object.
+             *
+             * @param file The file we want to open.
+             * @param read_which_entities Which OSM entities (nodes, ways, relations, and/or changesets)
+             *                            should be read from the input file. It can speed the read up
+             *                            significantly if objects that are not needed anyway are not
+             *                            parsed.
+             */
+            explicit Reader(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities = osmium::osm_entity_bits::all) :
+                m_file(file.check()),
+                m_read_which_entities(read_which_entities),
+                m_status(status::okay),
+                m_childpid(0),
+                m_input_queue(max_input_queue_size, "raw_input"),
+                m_decompressor(m_file.buffer() ?
+                    osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), m_file.buffer(), m_file.buffer_size()) :
+                    osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), open_input_file_or_url(m_file.filename(), &m_childpid))),
+                m_read_thread_manager(*m_decompressor.get(), m_input_queue),
+                m_osmdata_queue(max_osmdata_queue_size, "parser_results"),
+                m_osmdata_queue_wrapper(m_osmdata_queue),
+                m_header_future(),
+                m_header(),
+                m_thread() {
+                std::promise<osmium::io::Header> header_promise;
+                m_header_future = header_promise.get_future();
+                m_thread = osmium::thread::thread_handler{parser_thread, std::ref(m_file), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), read_which_entities};
+            }
+
+            explicit Reader(const std::string& filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
+                Reader(osmium::io::File(filename), read_types) {
+            }
+
+            explicit Reader(const char* filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
+                Reader(osmium::io::File(filename), read_types) {
+            }
+
+            Reader(const Reader&) = delete;
+            Reader& operator=(const Reader&) = delete;
+
+            Reader(Reader&&) = default;
+            Reader& operator=(Reader&&) = default;
+
+            ~Reader() noexcept {
+                try {
+                    close();
+                } catch (...) {
+                    // Ignore any exceptions because destructor must not throw.
+                }
+            }
+
+            /**
+             * Close down the Reader. A call to this is optional, because the
+             * destructor of Reader will also call this. But if you don't call
+             * this function first, you might miss an exception, because the
+             * destructor is not allowed to throw.
+             *
+             * @throws Some form of osmium::io_error when there is a problem.
+             */
+            void close() {
+                m_status = status::closed;
+
+                m_read_thread_manager.stop();
+
+                m_osmdata_queue_wrapper.drain();
+
+                try {
+                    m_read_thread_manager.close();
+                } catch (...) {
+                    // Ignore any exceptions.
+                }
+
+#ifndef _WIN32
+                if (m_childpid) {
+                    int status;
+                    pid_t pid = ::waitpid(m_childpid, &status, 0);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+                    if (pid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+                        throw std::system_error(errno, std::system_category(), "subprocess returned error");
+                    }
+#pragma GCC diagnostic pop
+                    m_childpid = 0;
+                }
+#endif
+            }
+
+            /**
+             * Get the header data from the file.
+             *
+             * @returns Header.
+             * @throws Some form of osmium::io_error if there is an error.
+             */
+            osmium::io::Header header() {
+                if (m_status == status::error) {
+                    throw io_error("Can not get header from reader when in status 'error'");
+                }
+
+                try {
+                    if (m_header_future.valid()) {
+                        m_header = m_header_future.get();
+                        if (m_read_which_entities == osmium::osm_entity_bits::nothing) {
+                            m_status = status::eof;
+                        }
+                    }
+                } catch (...) {
+                    close();
+                    m_status = status::error;
+                    throw;
+                }
+                return m_header;
+            }
+
+            /**
+             * Reads the next buffer from the input. An invalid buffer signals
+             * end-of-file. After end-of-file all read() calls will return an
+             * invalid buffer. An invalid buffer is also always returned if
+             * osmium::osm_entity_bits::nothing was set when the Reader was
+             * constructed.
+             *
+             * @returns Buffer.
+             * @throws Some form of osmium::io_error if there is an error.
+             */
+            osmium::memory::Buffer read() {
+                osmium::memory::Buffer buffer;
+
+                if (m_status != status::okay ||
+                    m_read_which_entities == osmium::osm_entity_bits::nothing) {
+                    throw io_error("Can not read from reader when in status 'closed', 'eof', or 'error'");
+                }
+
+                try {
+                    // m_input_format.read() can return an invalid buffer to signal EOF,
+                    // or a valid buffer with or without data. A valid buffer
+                    // without data is not an error, it just means we have to
+                    // keep getting the next buffer until there is one with data.
+                    while (true) {
+                        buffer = m_osmdata_queue_wrapper.pop();
+                        if (detail::at_end_of_data(buffer)) {
+                            m_status = status::eof;
+                            m_read_thread_manager.close();
+                            return buffer;
+                        }
+                        if (buffer.committed() > 0) {
+                            return buffer;
+                        }
+                    }
+                } catch (...) {
+                    close();
+                    m_status = status::error;
+                    throw;
+                }
+            }
+
+            /**
+             * Has the end of file been reached? This is set after the last
+             * data has been read. It is also set by calling close().
+             */
+            bool eof() const {
+                return m_status == status::eof || m_status == status::closed;
+            }
+
+        }; // class Reader
+
+        /**
+         * Read contents of the given file into a buffer in one go. Takes
+         * the same arguments as any of the Reader constructors.
+         *
+         * The buffer can take up quite a lot of memory, so don't do this
+         * unless you are working with small OSM files and/or have lots of
+         * RAM.
+         */
+        template <typename... TArgs>
+        osmium::memory::Buffer read_file(TArgs&&... args) {
+            osmium::memory::Buffer buffer(1024*1024, osmium::memory::Buffer::auto_grow::yes);
+
+            Reader reader(std::forward<TArgs>(args)...);
+            while (osmium::memory::Buffer read_buffer = reader.read()) {
+                buffer.add_buffer(read_buffer);
+                buffer.commit();
+            }
+
+            return buffer;
+        }
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_READER_HPP
diff --git a/contrib/libosmium/osmium/io/reader_iterator.hpp b/contrib/libosmium/osmium/io/reader_iterator.hpp
new file mode 100644
index 0000000..8620789
--- /dev/null
+++ b/contrib/libosmium/osmium/io/reader_iterator.hpp
@@ -0,0 +1,51 @@
+#ifndef OSMIUM_IO_READER_ITERATOR_HPP
+#define OSMIUM_IO_READER_ITERATOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/io/reader.hpp>
+#include <osmium/io/input_iterator.hpp>
+
+namespace std {
+
+    inline osmium::io::InputIterator<osmium::io::Reader> begin(osmium::io::Reader& reader) {
+        return osmium::io::InputIterator<osmium::io::Reader>(reader);
+    }
+
+    inline osmium::io::InputIterator<osmium::io::Reader> end(osmium::io::Reader&) {
+        return osmium::io::InputIterator<osmium::io::Reader>();
+    }
+
+} // namespace std
+
+#endif // OSMIUM_IO_READER_ITERATOR_HPP
diff --git a/contrib/libosmium/osmium/io/writer.hpp b/contrib/libosmium/osmium/io/writer.hpp
new file mode 100644
index 0000000..09c605c
--- /dev/null
+++ b/contrib/libosmium/osmium/io/writer.hpp
@@ -0,0 +1,344 @@
+#ifndef OSMIUM_IO_WRITER_HPP
+#define OSMIUM_IO_WRITER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <future>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/detail/queue_util.hpp>
+#include <osmium/io/detail/read_write.hpp>
+#include <osmium/io/detail/write_thread.hpp>
+#include <osmium/io/error.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/io/writer_options.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/thread/util.hpp>
+
+namespace osmium {
+
+    namespace io {
+
+        /**
+         * This is the user-facing interface for writing OSM files. Instantiate
+         * an object of this class with a file name or osmium::io::File object
+         * and optionally the data for the header and then call operator() on
+         * it to write Buffers or Items.
+         *
+         * The writer uses multithreading internally to do the actual encoding
+         * of the data into the intended format, possible compress the data and
+         * then write it out. But this is intentionally hidden from the user
+         * of this class who can use it without knowing those details.
+         *
+         * If you are done call the close() method to finish up. Only if you
+         * don't get an exception from the close() method, you can be sure
+         * the data is written correctly (modulo operating system buffering).
+         * The destructor of this class will also do the right thing if you
+         * forget to call close(), but because the destructor can't throw you
+         * will not get informed about any problems.
+         *
+         * The writer is usually used to write complete blocks of data stored
+         * in osmium::memory::Buffers. But you can also write single
+         * osmium::memory::Items. In this case the Writer uses an internal
+         * Buffer.
+         */
+        class Writer {
+
+            static constexpr size_t default_buffer_size = 10 * 1024 * 1024;
+
+            osmium::io::File m_file;
+
+            detail::future_string_queue_type m_output_queue;
+
+            std::unique_ptr<osmium::io::detail::OutputFormat> m_output;
+
+            osmium::memory::Buffer m_buffer;
+
+            size_t m_buffer_size;
+
+            std::future<bool> m_write_future;
+
+            osmium::thread::thread_handler m_thread;
+
+            enum class status {
+                okay   = 0, // normal writing
+                error  = 1, // some error occurred while writing
+                closed = 2  // close() called successfully
+            } m_status;
+
+            // This function will run in a separate thread.
+            static void write_thread(detail::future_string_queue_type& output_queue,
+                                     std::unique_ptr<osmium::io::Compressor>&& compressor,
+                                     std::promise<bool>&& write_promise) {
+                detail::WriteThread write_thread{output_queue,
+                                                 std::move(compressor),
+                                                 std::move(write_promise)};
+                write_thread();
+            }
+
+            void do_write(osmium::memory::Buffer&& buffer) {
+                if (buffer && buffer.committed() > 0) {
+                    m_output->write_buffer(std::move(buffer));
+                }
+            }
+
+            void do_flush() {
+                if (m_buffer && m_buffer.committed() > 0) {
+                    osmium::memory::Buffer buffer{m_buffer_size,
+                                                  osmium::memory::Buffer::auto_grow::no};
+                    using std::swap;
+                    swap(m_buffer, buffer);
+
+                    m_output->write_buffer(std::move(buffer));
+                }
+            }
+
+            template <typename TFunction, typename... TArgs>
+            void ensure_cleanup(TFunction func, TArgs&&... args) {
+                if (m_status != status::okay) {
+                    throw io_error("Can not write to writer when in status 'closed' or 'error'");
+                }
+
+                try {
+                    osmium::thread::check_for_exception(m_write_future);
+                    func(std::forward<TArgs>(args)...);
+                } catch (...) {
+                    m_status = status::error;
+                    detail::add_to_queue(m_output_queue, std::current_exception());
+                    detail::add_end_of_data_to_queue(m_output_queue);
+                    throw;
+                }
+            }
+
+            struct options_type {
+                osmium::io::Header header;
+                overwrite allow_overwrite = overwrite::no;
+                fsync sync = fsync::no;
+            };
+
+            static void set_option(options_type& options, const osmium::io::Header& header) {
+                options.header = header;
+            }
+
+            static void set_option(options_type& options, overwrite value) {
+                options.allow_overwrite = value;
+            }
+
+            static void set_option(options_type& options, fsync value) {
+                options.sync = value;
+            }
+
+        public:
+
+            /**
+             * The constructor of the Writer object opens a file and writes the
+             * header to it.
+             *
+             * @param file File (contains name and format info) to open.
+             * @param args All further arguments are optional and can appear
+             *             in any order:
+             *
+             * * osmium::io::Header: Optional header data. If this is
+             *       not given, a default constructed osmium::io::Header
+             *       object will be used.
+             *
+             * * osmium::io::overwrite: Allow overwriting of existing file?
+             *       Can be osmium::io::overwrite::allow or
+             *       osmium::io::overwrite::no (default).
+             *
+             * * osmium::io::fsync: Should fsync be called on the file
+             *       before closing it? Can be osmium::io::fsync::yes or
+             *       osmium::io::fsync::no (default).
+             *
+             * @throws osmium::io_error If there was an error.
+             * @throws std::system_error If the file could not be opened.
+             */
+            template <typename... TArgs>
+            explicit Writer(const osmium::io::File& file, TArgs&&... args) :
+                m_file(file.check()),
+                m_output_queue(20, "raw_output"), // XXX
+                m_output(osmium::io::detail::OutputFormatFactory::instance().create_output(m_file, m_output_queue)),
+                m_buffer(),
+                m_buffer_size(default_buffer_size),
+                m_write_future(),
+                m_thread(),
+                m_status(status::okay) {
+                assert(!m_file.buffer()); // XXX can't handle pseudo-files
+
+                options_type options;
+                (void)std::initializer_list<int>{
+                    (set_option(options, args), 0)...
+                };
+
+                std::unique_ptr<osmium::io::Compressor> compressor =
+                    CompressionFactory::instance().create_compressor(file.compression(),
+                                                                     osmium::io::detail::open_for_writing(m_file.filename(), options.allow_overwrite),
+                                                                     options.sync);
+
+                std::promise<bool> write_promise;
+                m_write_future = write_promise.get_future();
+                m_thread = osmium::thread::thread_handler{write_thread, std::ref(m_output_queue), std::move(compressor), std::move(write_promise)};
+
+                ensure_cleanup([&](){
+                    m_output->write_header(options.header);
+                });
+            }
+
+            template <typename... TArgs>
+            explicit Writer(const std::string& filename, TArgs&&... args) :
+                Writer(osmium::io::File(filename), std::forward<TArgs>(args)...) {
+            }
+
+            template <typename... TArgs>
+            explicit Writer(const char* filename, TArgs&&... args) :
+                Writer(osmium::io::File(filename), std::forward<TArgs>(args)...) {
+            }
+
+            Writer(const Writer&) = delete;
+            Writer& operator=(const Writer&) = delete;
+
+            Writer(Writer&&) = default;
+            Writer& operator=(Writer&&) = default;
+
+            ~Writer() noexcept {
+                try {
+                    close();
+                } catch (...) {
+                    // Ignore any exceptions because destructor must not throw.
+                }
+            }
+
+            /**
+             * Get the currently configured size of the internal buffer.
+             */
+            size_t buffer_size() const noexcept {
+                return m_buffer_size;
+            }
+
+            /**
+             * Set the size of the internal buffer. This will only take effect
+             * if you have not yet written anything or after the next flush().
+             */
+            void set_buffer_size(size_t size) noexcept {
+                m_buffer_size = size;
+            }
+
+            /**
+             * Flush the internal buffer if it contains any data. This is
+             * usually not needed as the buffer gets flushed on close()
+             * automatically.
+             *
+             * @throws Some form of osmium::io_error when there is a problem.
+             */
+            void flush() {
+                ensure_cleanup([&](){
+                    do_flush();
+                });
+            }
+
+            /**
+             * Write contents of a buffer to the output file. The buffer is
+             * moved into this function and will be in an undefined moved-from
+             * state afterwards.
+             *
+             * @param buffer Buffer that is being written out.
+             * @throws Some form of osmium::io_error when there is a problem.
+             */
+            void operator()(osmium::memory::Buffer&& buffer) {
+                ensure_cleanup([&](){
+                    do_flush();
+                    do_write(std::move(buffer));
+                });
+            }
+
+            /**
+             * Add item to the internal buffer for eventual writing to the
+             * output file.
+             *
+             * @param item Item to write (usually an OSM object).
+             * @throws Some form of osmium::io_error when there is a problem.
+             */
+            void operator()(const osmium::memory::Item& item) {
+                ensure_cleanup([&](){
+                    if (!m_buffer) {
+                        m_buffer = osmium::memory::Buffer{m_buffer_size,
+                                                          osmium::memory::Buffer::auto_grow::no};
+                    }
+                    try {
+                        m_buffer.push_back(item);
+                    } catch (osmium::buffer_is_full&) {
+                        do_flush();
+                        m_buffer.push_back(item);
+                    }
+                });
+            }
+
+            /**
+             * Flushes internal buffer and closes output file. If you do not
+             * call this, the destructor of Writer will also do the same
+             * thing. But because this call might throw an exception, which
+             * the destructor will ignore, it is better to call close()
+             * explicitly.
+             *
+             * @throws Some form of osmium::io_error when there is a problem.
+             */
+            void close() {
+                if (m_status == status::okay) {
+                    ensure_cleanup([&](){
+                        do_write(std::move(m_buffer));
+                        m_output->write_end();
+                        m_status = status::closed;
+                        detail::add_end_of_data_to_queue(m_output_queue);
+                    });
+                }
+
+                if (m_write_future.valid()) {
+                    m_write_future.get();
+                }
+            }
+
+        }; // class Writer
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_WRITER_HPP
diff --git a/contrib/libosmium/osmium/io/writer_options.hpp b/contrib/libosmium/osmium/io/writer_options.hpp
new file mode 100644
index 0000000..ef19553
--- /dev/null
+++ b/contrib/libosmium/osmium/io/writer_options.hpp
@@ -0,0 +1,60 @@
+#ifndef OSMIUM_IO_WRITER_OPTIONS_HPP
+#define OSMIUM_IO_WRITER_OPTIONS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+namespace osmium {
+
+    namespace io {
+
+        /**
+         * Allow overwriting of existing file?
+         */
+        enum class overwrite : bool {
+            no    = false,
+            allow = true
+        };
+
+        /**
+         * Should writer do an fsync before closing the file?
+         */
+        enum class fsync : bool {
+            no  = false,
+            yes = true
+        };
+
+    } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_WRITER_OPTIONS_HPP
diff --git a/contrib/libosmium/osmium/io/xml_input.hpp b/contrib/libosmium/osmium/io/xml_input.hpp
new file mode 100644
index 0000000..dfcd0a9
--- /dev/null
+++ b/contrib/libosmium/osmium/io/xml_input.hpp
@@ -0,0 +1,48 @@
+#ifndef OSMIUM_IO_XML_INPUT_HPP
+#define OSMIUM_IO_XML_INPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * Include this file if you want to read OSM XML files.
+ *
+ * @attention If you include this file, you'll need to link with
+ *            `libexpat`, and enable multithreading.
+ */
+
+#include <osmium/io/reader.hpp> // IWYU pragma: export
+#include <osmium/io/detail/xml_input_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_XML_INPUT_HPP
diff --git a/contrib/libosmium/osmium/io/xml_output.hpp b/contrib/libosmium/osmium/io/xml_output.hpp
new file mode 100644
index 0000000..18a1386
--- /dev/null
+++ b/contrib/libosmium/osmium/io/xml_output.hpp
@@ -0,0 +1,47 @@
+#ifndef OSMIUM_IO_XML_OUTPUT_HPP
+#define OSMIUM_IO_XML_OUTPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+/**
+ * @file
+ *
+ * Include this file if you want to write OSM XML files.
+ *
+ * @attention If you include this file, you'll need to enable multithreading.
+ */
+
+#include <osmium/io/writer.hpp> // IWYU pragma: export
+#include <osmium/io/detail/xml_output_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_XML_OUTPUT_HPP
diff --git a/contrib/libosmium/osmium/memory/buffer.hpp b/contrib/libosmium/osmium/memory/buffer.hpp
new file mode 100644
index 0000000..11a4c97
--- /dev/null
+++ b/contrib/libosmium/osmium/memory/buffer.hpp
@@ -0,0 +1,617 @@
+#ifndef OSMIUM_MEMORY_BUFFER_HPP
+#define OSMIUM_MEMORY_BUFFER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <functional>
+#include <iterator>
+#include <stdexcept>
+#include <utility>
+#include <vector>
+
+#include <osmium/memory/item.hpp>
+#include <osmium/memory/item_iterator.hpp>
+#include <osmium/osm/entity.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception thrown by the osmium::memory::Buffer class when somebody tries
+     * to write data into a buffer and it doesn't fit. Buffers with internal
+     * memory management will not throw this exception, but increase their size.
+     */
+    struct buffer_is_full : public std::runtime_error {
+
+        buffer_is_full() :
+            std::runtime_error("Osmium buffer is full") {
+        }
+
+    }; // struct buffer_is_full
+
+    /**
+     * @brief Memory management of items in buffers and iterators over this data.
+     */
+    namespace memory {
+
+        /**
+         * A memory area for storing OSM objects and other items. Each item stored
+         * has a type and a length. See the Item class for details.
+         *
+         * Data can be added to a buffer piece by piece using reserve_space() and
+         * add_item(). After all data that together forms an item is added, it must
+         * be committed using the commit() call. Usually this is done through the
+         * Builder class and its derived classes.
+         *
+         * You can iterate over all items in a buffer using the iterators returned
+         * by begin(), end(), cbegin(), and cend().
+         *
+         * Buffers exist in two flavours, those with external memory management and
+         * those with internal memory management. If you already have some memory
+         * with data in it (for instance read from disk), you create a Buffer with
+         * external memory management. It is your job then to free the memory once
+         * the buffer isn't used any more. If you don't have memory already, you can
+         * create a Buffer object and have it manage the memory internally. It will
+         * dynamically allocate memory and free it again after use.
+         *
+         * By default, if a buffer gets full it will throw a buffer_is_full exception.
+         * You can use the set_full_callback() method to set a callback functor
+         * which will be called instead of throwing an exception.
+         */
+        class Buffer {
+
+        public:
+
+            enum class auto_grow : bool {
+                yes = true,
+                no  = false
+            }; // enum class auto_grow
+
+        private:
+
+            std::vector<unsigned char> m_memory;
+            unsigned char* m_data;
+            size_t m_capacity;
+            size_t m_written;
+            size_t m_committed;
+            auto_grow m_auto_grow {auto_grow::no};
+            std::function<void(Buffer&)> m_full;
+
+        public:
+
+            typedef Item value_type;
+
+            /**
+             * The constructor without any parameters creates a non-initialized
+             * buffer, ie an empty hull of a buffer that has no actual memory
+             * associated with it. It can be used to signify end-of-data.
+             */
+            Buffer() noexcept :
+                m_memory(),
+                m_data(nullptr),
+                m_capacity(0),
+                m_written(0),
+                m_committed(0) {
+            }
+
+            /**
+             * Constructs an externally memory-managed buffer using the given
+             * memory and size.
+             *
+             * @param data A pointer to some already initialized data.
+             * @param size The size of the initialized data.
+             * @throws std::invalid_argument When the size isn't a multiple of the alignment.
+             */
+            explicit Buffer(unsigned char* data, size_t size) :
+                m_memory(),
+                m_data(data),
+                m_capacity(size),
+                m_written(size),
+                m_committed(size) {
+                if (size % align_bytes != 0) {
+                    throw std::invalid_argument("buffer size needs to be multiple of alignment");
+                }
+            }
+
+            /**
+             * Constructs an externally memory-managed buffer with the given
+             * capacity that already contains 'committed' bytes of data.
+             *
+             * @param data A pointer to some (possibly initialized) data.
+             * @param capacity The size of the memory for this buffer.
+             * @param committed The size of the initialized data. If this is 0, the buffer startes out empty.
+             * @throws std::invalid_argument When the capacity or committed isn't a multiple of the alignment.
+             */
+            explicit Buffer(unsigned char* data, size_t capacity, size_t committed) :
+                m_memory(),
+                m_data(data),
+                m_capacity(capacity),
+                m_written(committed),
+                m_committed(committed) {
+                if (capacity % align_bytes != 0) {
+                    throw std::invalid_argument("buffer capacity needs to be multiple of alignment");
+                }
+                if (committed % align_bytes != 0) {
+                    throw std::invalid_argument("buffer parameter 'committed' needs to be multiple of alignment");
+                }
+            }
+
+            /**
+             * Create an internally memory-managed buffer with the given capacity.
+             * different in that it internally gets dynamic memory of the
+             * required size. The dynamic memory will be automatically
+             * freed when the Buffer is destroyed.
+             */
+            explicit Buffer(size_t capacity, auto_grow auto_grow = auto_grow::yes) :
+                m_memory(capacity),
+                m_data(m_memory.data()),
+                m_capacity(capacity),
+                m_written(0),
+                m_committed(0),
+                m_auto_grow(auto_grow) {
+                if (capacity % align_bytes != 0) {
+                    throw std::invalid_argument("buffer capacity needs to be multiple of alignment");
+                }
+            }
+
+            // buffers can not be copied
+            Buffer(const Buffer&) = delete;
+            Buffer& operator=(const Buffer&) = delete;
+
+            // buffers can be moved
+            Buffer(Buffer&&) = default;
+            Buffer& operator=(Buffer&&) = default;
+
+            ~Buffer() = default;
+
+            /**
+             * Return a pointer to data inside the buffer.
+             */
+            unsigned char* data() const noexcept {
+                assert(m_data);
+                return m_data;
+            }
+
+            /**
+             * Returns the capacity of the buffer, ie how many bytes it can contain.
+             * Always returns 0 on invalid buffers.
+             */
+            size_t capacity() const noexcept {
+                return m_capacity;
+            }
+
+            /**
+             * Returns the number of bytes already filled in this buffer.
+             * Always returns 0 on invalid buffers.
+             */
+            size_t committed() const noexcept {
+                return m_committed;
+            }
+
+            /**
+             * Returns the number of bytes currently filled in this buffer that
+             * are not yet committed.
+             * Always returns 0 on invalid buffers.
+             */
+            size_t written() const noexcept {
+                return m_written;
+            }
+
+            /**
+             * This tests if the current state of the buffer is aligned
+             * properly. Can be used for asserts.
+             *
+             * The behaviour is undefined if you call this on an invalid
+             * buffer.
+             */
+            bool is_aligned() const noexcept {
+                assert(m_data);
+                return (m_written % align_bytes == 0) && (m_committed % align_bytes == 0);
+            }
+
+            /**
+             * Set functor to be called whenever the buffer is full
+             * instead of throwing buffer_is_full.
+             *
+             * The behaviour is undefined if you call this on an invalid
+             * buffer.
+             */
+            void set_full_callback(std::function<void(Buffer&)> full) {
+                assert(m_data);
+                m_full = full;
+            }
+
+            /**
+             * Grow capacity of this buffer to the given size.
+             * This works only with internally memory-managed buffers.
+             * If the given size is not larger than the current capacity, nothing is done.
+             * Already written but not committed data is discarded.
+             *
+             * The behaviour is undefined if you call this on an invalid
+             * buffer.
+             *
+             * @param size New capacity.
+             */
+            void grow(size_t size) {
+                assert(m_data);
+                if (m_memory.empty()) {
+                    throw std::logic_error("Can't grow Buffer if it doesn't use internal memory management.");
+                }
+                if (m_capacity < size) {
+                    if (size % align_bytes != 0) {
+                        throw std::invalid_argument("buffer capacity needs to be multiple of alignment");
+                    }
+                    m_memory.resize(size);
+                    m_data = m_memory.data();
+                    m_capacity = size;
+                }
+            }
+
+            /**
+             * Mark currently written bytes in the buffer as committed.
+             *
+             * The behaviour is undefined if you call this on an invalid
+             * buffer.
+             *
+             * @returns Last number of committed bytes before this commit.
+             */
+            size_t commit() {
+                assert(m_data);
+                assert(is_aligned());
+
+                const size_t offset = m_committed;
+                m_committed = m_written;
+                return offset;
+            }
+
+            /**
+             * Roll back changes in buffer to last committed state.
+             *
+             * The behaviour is undefined if you call this on an invalid
+             * buffer.
+             */
+            void rollback() {
+                assert(m_data);
+                m_written = m_committed;
+            }
+
+            /**
+             * Clear the buffer.
+             *
+             * No-op on an invalid buffer.
+             *
+             * @returns Number of bytes in the buffer before it was cleared.
+             */
+            size_t clear() {
+                const size_t committed = m_committed;
+                m_written = 0;
+                m_committed = 0;
+                return committed;
+            }
+
+            /**
+             * Get the data in the buffer at the given offset.
+             *
+             * The behaviour is undefined if you call this on an invalid
+             * buffer.
+             *
+             * @tparam T Type we want to the data to be interpreted as.
+             * @returns Reference of given type pointing to the data in the buffer.
+             */
+            template <typename T>
+            T& get(const size_t offset) const {
+                assert(m_data);
+                return *reinterpret_cast<T*>(&m_data[offset]);
+            }
+
+            /**
+             * Reserve space of given size in buffer and return pointer to it.
+             * This is the only way of adding data to the buffer. You reserve
+             * the space and then fill it.
+             *
+             * Note that you have to eventually call commit() to actually
+             * commit this data.
+             *
+             * If there isn't enough space in the buffer, one of three things
+             * can happen:
+             *
+             * * If you have set a callback with set_full_callback(), it is
+             *   called. After the call returns, you must have either grown
+             *   the buffer or cleared it by calling buffer.clear().
+             * * If no callback is defined and this buffer uses internal
+             *   memory management, the buffers capacity is grown, so that
+             *   the new data will fit.
+             * * Else the buffer_is_full exception is thrown.
+             *
+             * The behaviour is undefined if you call this on an invalid
+             * buffer.
+             *
+             * @param size Number of bytes to reserve.
+             * @returns Pointer to reserved space. Note that this pointer is
+             *         only guaranteed to be valid until the next call to
+             *         reserve_space().
+             * @throws osmium::buffer_is_full Might be thrown if the buffer is full.
+             */
+            unsigned char* reserve_space(const size_t size) {
+                assert(m_data);
+                if (m_written + size > m_capacity) {
+                    if (m_full) {
+                        m_full(*this);
+                    } else if (!m_memory.empty() && (m_auto_grow == auto_grow::yes)) {
+                        // double buffer size until there is enough space
+                        size_t new_capacity = m_capacity * 2;
+                        while (m_written + size > new_capacity) {
+                            new_capacity *= 2;
+                        }
+                        grow(new_capacity);
+                    } else {
+                        throw osmium::buffer_is_full();
+                    }
+                }
+                unsigned char* data = &m_data[m_written];
+                m_written += size;
+                return data;
+            }
+
+            /**
+             * Add an item to the buffer. The size of the item is stored inside
+             * the item, so we know how much memory to copy.
+             *
+             * Note that you have to eventually call commit() to actually
+             * commit this data.
+             *
+             * The behaviour is undefined if you call this on an invalid
+             * buffer.
+             *
+             * @tparam T Class of the item to be copied.
+             * @param item Reference to the item to be copied.
+             * @returns Reference to newly copied data in the buffer.
+             */
+            template <typename T>
+            T& add_item(const T& item) {
+                assert(m_data);
+                unsigned char* target = reserve_space(item.padded_size());
+                std::copy_n(reinterpret_cast<const unsigned char*>(&item), item.padded_size(), target);
+                return *reinterpret_cast<T*>(target);
+            }
+
+            /**
+             * Add committed contents of the given buffer to this buffer.
+             *
+             * The behaviour is undefined if you call this on an invalid
+             * buffer.
+             *
+             * Note that you have to eventually call commit() to actually
+             * commit this data.
+             */
+            void add_buffer(const Buffer& buffer) {
+                assert(m_data);
+                unsigned char* target = reserve_space(buffer.committed());
+                std::copy_n(reinterpret_cast<const unsigned char*>(buffer.data()), buffer.committed(), target);
+            }
+
+            /**
+             * Add an item to the buffer. This function is provided so that
+             * you can use std::back_inserter.
+             *
+             * The behaviour is undefined if you call this on an invalid
+             * buffer.
+             */
+            void push_back(const osmium::memory::Item& item) {
+                assert(m_data);
+                add_item(item);
+                commit();
+            }
+
+            /**
+             * These iterators can be used to iterate over all items in
+             * a buffer.
+             */
+            template <typename T>
+            using t_iterator = osmium::memory::ItemIterator<T>;
+
+            template <typename T>
+            using t_const_iterator = osmium::memory::ItemIterator<const T>;
+
+            typedef t_iterator<osmium::OSMEntity> iterator;
+            typedef t_const_iterator<osmium::OSMEntity> const_iterator;
+
+            template <typename T>
+            t_iterator<T> begin() {
+                assert(m_data);
+                return t_iterator<T>(m_data, m_data + m_committed);
+            }
+
+            iterator begin() {
+                assert(m_data);
+                return iterator(m_data, m_data + m_committed);
+            }
+
+            template <typename T>
+            t_iterator<T> get_iterator(size_t offset) {
+                assert(m_data);
+                return t_iterator<T>(m_data + offset, m_data + m_committed);
+            }
+
+            iterator get_iterator(size_t offset) {
+                assert(m_data);
+                return iterator(m_data + offset, m_data + m_committed);
+            }
+
+            template <typename T>
+            t_iterator<T> end() {
+                assert(m_data);
+                return t_iterator<T>(m_data + m_committed, m_data + m_committed);
+            }
+
+            iterator end() {
+                assert(m_data);
+                return iterator(m_data + m_committed, m_data + m_committed);
+            }
+
+            template <typename T>
+            t_const_iterator<T> cbegin() const {
+                assert(m_data);
+                return t_const_iterator<T>(m_data, m_data + m_committed);
+            }
+
+            const_iterator cbegin() const {
+                assert(m_data);
+                return const_iterator(m_data, m_data + m_committed);
+            }
+
+            template <typename T>
+            t_const_iterator<T> get_iterator(size_t offset) const {
+                assert(m_data);
+                return t_const_iterator<T>(m_data + offset, m_data + m_committed);
+            }
+
+            const_iterator get_iterator(size_t offset) const {
+                assert(m_data);
+                return const_iterator(m_data + offset, m_data + m_committed);
+            }
+
+            template <typename T>
+            t_const_iterator<T> cend() const {
+                assert(m_data);
+                return t_const_iterator<T>(m_data + m_committed, m_data + m_committed);
+            }
+
+            const_iterator cend() const {
+                assert(m_data);
+                return const_iterator(m_data + m_committed, m_data + m_committed);
+            }
+
+            template <typename T>
+            t_const_iterator<T> begin() const {
+                return cbegin<T>();
+            }
+
+            const_iterator begin() const {
+                return cbegin();
+            }
+
+            template <typename T>
+            t_const_iterator<T> end() const {
+                return cend<T>();
+            }
+
+            const_iterator end() const {
+                return cend();
+            }
+
+            /**
+             * In a bool context any initialized buffer is true.
+             */
+            explicit operator bool() const {
+                return m_data != nullptr;
+            }
+
+            friend void swap(Buffer& lhs, Buffer& rhs) {
+                using std::swap;
+
+                swap(lhs.m_memory, rhs.m_memory);
+                swap(lhs.m_data, rhs.m_data);
+                swap(lhs.m_capacity, rhs.m_capacity);
+                swap(lhs.m_written, rhs.m_written);
+                swap(lhs.m_committed, rhs.m_committed);
+            }
+
+            /**
+             * Purge removed items from the buffer. This is done by moving all
+             * non-removed items forward in the buffer overwriting removed
+             * items and then correcting the m_written and m_committed numbers.
+             *
+             * Note that calling this function invalidates all iterators on this
+             * buffer and all offsets in this buffer.
+             *
+             * For every non-removed item that moves its position, the function
+             * 'moving_in_buffer' is called on the given callback object with
+             * the old and new offsets in the buffer where the object used to
+             * be and is now, respectively. This call can be used to update any
+             * indexes.
+             *
+             * The behaviour is undefined if you call this on an invalid
+             * buffer.
+             */
+            template <typename TCallbackClass>
+            void purge_removed(TCallbackClass* callback) {
+                assert(m_data);
+                if (begin() == end()) {
+                    return;
+                }
+
+                iterator it_write = begin();
+
+                iterator next;
+                for (iterator it_read = begin(); it_read != end(); it_read = next) {
+                    next = std::next(it_read);
+                    if (!it_read->removed()) {
+                        if (it_read != it_write) {
+                            assert(it_read.data() >= data());
+                            assert(it_write.data() >= data());
+                            size_t old_offset = static_cast<size_t>(it_read.data() - data());
+                            size_t new_offset = static_cast<size_t>(it_write.data() - data());
+                            callback->moving_in_buffer(old_offset, new_offset);
+                            std::memmove(it_write.data(), it_read.data(), it_read->padded_size());
+                        }
+                        it_write.advance_once();
+                    }
+                }
+
+                assert(it_write.data() >= data());
+                m_written = static_cast<size_t>(it_write.data() - data());
+                m_committed = m_written;
+            }
+
+        }; // class Buffer
+
+        inline bool operator==(const Buffer& lhs, const Buffer& rhs) noexcept {
+            if (!lhs || !rhs) {
+                return !lhs && !rhs;
+            }
+            return lhs.data() == rhs.data() && lhs.capacity() == rhs.capacity() && lhs.committed() == rhs.committed();
+        }
+
+        inline bool operator!=(const Buffer& lhs, const Buffer& rhs) noexcept {
+            return ! (lhs == rhs);
+        }
+
+    } // namespace memory
+
+} // namespace osmium
+
+#endif // OSMIUM_MEMORY_BUFFER_HPP
diff --git a/contrib/libosmium/osmium/memory/collection.hpp b/contrib/libosmium/osmium/memory/collection.hpp
new file mode 100644
index 0000000..54a97f5
--- /dev/null
+++ b/contrib/libosmium/osmium/memory/collection.hpp
@@ -0,0 +1,153 @@
+#ifndef OSMIUM_MEMORY_COLLECTION_HPP
+#define OSMIUM_MEMORY_COLLECTION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iterator>
+#include <iosfwd>
+#include <type_traits>
+
+#include <osmium/memory/item.hpp>
+
+namespace osmium {
+
+    namespace memory {
+
+        template <typename TMember>
+        class CollectionIterator : public std::iterator<std::forward_iterator_tag, TMember> {
+
+            // This data_type is either 'unsigned char*' or 'const unsigned char*' depending
+            // on whether TMember is const. This allows this class to be used as an iterator and
+            // as a const_iterator.
+            typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type;
+
+            data_type m_data;
+
+        public:
+
+            CollectionIterator() noexcept :
+                m_data(nullptr) {
+            }
+
+            CollectionIterator(data_type data) noexcept :
+                m_data(data) {
+            }
+
+            CollectionIterator<TMember>& operator++() {
+                m_data = reinterpret_cast<TMember*>(m_data)->next();
+                return *static_cast<CollectionIterator<TMember>*>(this);
+            }
+
+            CollectionIterator<TMember> operator++(int) {
+                CollectionIterator<TMember> tmp(*this);
+                operator++();
+                return tmp;
+            }
+
+            bool operator==(const CollectionIterator<TMember>& rhs) const noexcept {
+                return m_data == rhs.m_data;
+            }
+
+            bool operator!=(const CollectionIterator<TMember>& rhs) const noexcept {
+                return m_data != rhs.m_data;
+            }
+
+            unsigned char* data() const noexcept {
+                return m_data;
+            }
+
+            TMember& operator*() const {
+                return *reinterpret_cast<TMember*>(m_data);
+            }
+
+            TMember* operator->() const {
+                return reinterpret_cast<TMember*>(m_data);
+            }
+
+            template <typename TChar, typename TTraits>
+            friend std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const CollectionIterator<TMember>& iter) {
+                return out << static_cast<const void*>(iter.m_data);
+            }
+
+        }; // class CollectionIterator
+
+        template <typename TMember, osmium::item_type TCollectionItemType>
+        class Collection : public Item {
+
+        public:
+
+            typedef CollectionIterator<TMember> iterator;
+            typedef CollectionIterator<const TMember> const_iterator;
+            typedef TMember value_type;
+
+            static constexpr osmium::item_type itemtype = TCollectionItemType;
+
+            Collection() :
+                Item(sizeof(Collection<TMember, TCollectionItemType>), TCollectionItemType) {
+            }
+
+            bool empty() const {
+                return sizeof(Collection<TMember, TCollectionItemType>) == byte_size();
+            }
+
+            iterator begin() {
+                return iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
+            }
+
+            iterator end() {
+                return iterator(data() + byte_size());
+            }
+
+            const_iterator cbegin() const {
+                return const_iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
+            }
+
+            const_iterator cend() const {
+                return const_iterator(data() + byte_size());
+            }
+
+            const_iterator begin() const {
+                return cbegin();
+            }
+
+            const_iterator end() const {
+                return cend();
+            }
+
+        }; // class Collection
+
+    } // namespace memory
+
+} // namespace osmium
+
+#endif // OSMIUM_MEMORY_COLLECTION_HPP
diff --git a/contrib/libosmium/osmium/memory/item.hpp b/contrib/libosmium/osmium/memory/item.hpp
new file mode 100644
index 0000000..30c5377
--- /dev/null
+++ b/contrib/libosmium/osmium/memory/item.hpp
@@ -0,0 +1,177 @@
+#ifndef OSMIUM_MEMORY_ITEM_HPP
+#define OSMIUM_MEMORY_ITEM_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdint>
+#include <type_traits>
+
+namespace osmium {
+
+    // forward declaration, see osmium/osm/item_type.hpp for declaration
+    enum class item_type : uint16_t;
+
+    namespace builder {
+        class Builder;
+    }
+
+    namespace memory {
+
+        typedef uint32_t item_size_type;
+
+        // align datastructures to this many bytes
+        constexpr item_size_type align_bytes = 8;
+
+        template <typename T>
+        inline T padded_length(T length) noexcept {
+            static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, "Template parameter must be unsigned integral type");
+            return (length + align_bytes - 1) & ~(align_bytes - 1);
+        }
+
+        /**
+         * @brief Namespace for Osmium internal use
+         */
+        namespace detail {
+
+            /**
+            * This class contains only a helper method used in several
+            * other classes.
+            */
+            class ItemHelper {
+
+            protected:
+
+                ItemHelper() = default;
+
+                ~ItemHelper() = default;
+
+                ItemHelper(const ItemHelper&) = default;
+                ItemHelper(ItemHelper&&) = default;
+
+                ItemHelper& operator=(const ItemHelper&) = default;
+                ItemHelper& operator=(ItemHelper&&) = default;
+
+            public:
+
+                unsigned char* data() noexcept {
+                    return reinterpret_cast<unsigned char*>(this);
+                }
+
+                const unsigned char* data() const noexcept {
+                    return reinterpret_cast<const unsigned char*>(this);
+                }
+
+            }; // class ItemHelper
+
+        } // namespace detail
+
+        class Item : public osmium::memory::detail::ItemHelper {
+
+            item_size_type m_size;
+            item_type m_type;
+            uint16_t m_removed : 1;
+            uint16_t m_padding : 15;
+
+            template <typename TMember>
+            friend class CollectionIterator;
+
+            template <typename TMember>
+            friend class ItemIterator;
+
+            friend class osmium::builder::Builder;
+
+            Item& add_size(const item_size_type size) noexcept {
+                m_size += size;
+                return *this;
+            }
+
+        protected:
+
+            explicit Item(item_size_type size = 0, item_type type = item_type()) noexcept :
+                m_size(size),
+                m_type(type),
+                m_removed(false),
+                m_padding(0) {
+            }
+
+            Item(const Item&) = delete;
+            Item(Item&&) = delete;
+
+            Item& operator=(const Item&) = delete;
+            Item& operator=(Item&&) = delete;
+
+            Item& set_type(const item_type item_type) noexcept {
+                m_type = item_type;
+                return *this;
+            }
+
+        public:
+
+            unsigned char* next() noexcept {
+                return data() + padded_size();
+            }
+
+            const unsigned char* next() const noexcept {
+                return data() + padded_size();
+            }
+
+            item_size_type byte_size() const noexcept {
+                return m_size;
+            }
+
+            item_size_type padded_size() const {
+                return padded_length(m_size);
+            }
+
+            item_type type() const noexcept {
+                return m_type;
+            }
+
+            bool removed() const noexcept {
+                return m_removed;
+            }
+
+            void set_removed(bool removed) noexcept {
+                m_removed = removed;
+            }
+
+        }; // class Item
+
+        static_assert(sizeof(Item) == 8, "Class osmium::Item has wrong size!");
+        static_assert(sizeof(Item) % align_bytes == 0, "Class osmium::Item has wrong size to be aligned properly!");
+
+    } // namespace memory
+
+} // namespace osmium
+
+#endif // OSMIUM_MEMORY_ITEM_HPP
diff --git a/contrib/libosmium/osmium/memory/item_iterator.hpp b/contrib/libosmium/osmium/memory/item_iterator.hpp
new file mode 100644
index 0000000..c6b4205
--- /dev/null
+++ b/contrib/libosmium/osmium/memory/item_iterator.hpp
@@ -0,0 +1,234 @@
+#ifndef OSMIUM_ITEM_ITERATOR_HPP
+#define OSMIUM_ITEM_ITERATOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <iterator>
+#include <iosfwd>
+#include <type_traits>
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+    class Node;
+    class Way;
+    class Relation;
+    class Area;
+    class Changeset;
+    class OSMObject;
+    class OSMEntity;
+    class TagList;
+    class WayNodeList;
+    class RelationMemberList;
+    class InnerRing;
+    class OuterRing;
+
+    namespace memory {
+
+        namespace detail {
+
+            template <typename T>
+            inline bool type_is_compatible(osmium::item_type) noexcept {
+                return true;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::Node>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::node;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::Way>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::way;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::Relation>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::relation;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::Area>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::area;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::Changeset>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::changeset;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::OSMObject>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::node || t == osmium::item_type::way || t == osmium::item_type::relation || t == osmium::item_type::area;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::OSMEntity>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::node || t == osmium::item_type::way || t == osmium::item_type::relation || t == osmium::item_type::area || t == osmium::item_type::changeset;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::TagList>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::tag_list;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::WayNodeList>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::way_node_list;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::RelationMemberList>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::relation_member_list || t == osmium::item_type::relation_member_list_with_full_members;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::OuterRing>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::outer_ring;
+            }
+
+            template <>
+            inline bool type_is_compatible<osmium::InnerRing>(osmium::item_type t) noexcept {
+                return t == osmium::item_type::inner_ring;
+            }
+
+        } // namespace detail
+
+        template <typename TMember>
+        class ItemIterator : public std::iterator<std::forward_iterator_tag, TMember> {
+
+            static_assert(std::is_base_of<osmium::memory::Item, TMember>::value, "TMember must derive from osmium::memory::Item");
+
+            // This data_type is either 'unsigned char*' or 'const unsigned char*' depending
+            // on whether TMember is const. This allows this class to be used as an iterator and
+            // as a const_iterator.
+            typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type;
+
+            data_type m_data;
+            data_type m_end;
+
+            void advance_to_next_item_of_right_type() {
+                while (m_data != m_end &&
+                       !detail::type_is_compatible<typename std::remove_const<TMember>::type>(reinterpret_cast<const osmium::memory::Item*>(m_data)->type())) {
+                    m_data = reinterpret_cast<TMember*>(m_data)->next();
+                }
+            }
+
+        public:
+
+            ItemIterator() noexcept :
+                m_data(nullptr),
+                m_end(nullptr) {
+            }
+
+            ItemIterator(data_type data, data_type end) :
+                m_data(data),
+                m_end(end) {
+                advance_to_next_item_of_right_type();
+            }
+
+            template <typename T>
+            ItemIterator<T> cast() const {
+                return ItemIterator<T>(m_data, m_end);
+            }
+
+            ItemIterator<TMember>& operator++() {
+                assert(m_data);
+                assert(m_data != m_end);
+                m_data = reinterpret_cast<TMember*>(m_data)->next();
+                advance_to_next_item_of_right_type();
+                return *static_cast<ItemIterator<TMember>*>(this);
+            }
+
+            /**
+             * Like operator++() but will NOT skip items of unwanted
+             * types. Do not use this unless you know what you are
+             * doing.
+             */
+            ItemIterator<TMember>& advance_once() {
+                assert(m_data);
+                assert(m_data != m_end);
+                m_data = reinterpret_cast<TMember*>(m_data)->next();
+                return *static_cast<ItemIterator<TMember>*>(this);
+            }
+
+            ItemIterator<TMember> operator++(int) {
+                ItemIterator<TMember> tmp(*this);
+                operator++();
+                return tmp;
+            }
+
+            bool operator==(const ItemIterator<TMember>& rhs) const {
+                return m_data == rhs.m_data && m_end == rhs.m_end;
+            }
+
+            bool operator!=(const ItemIterator<TMember>& rhs) const {
+                return !(*this == rhs);
+            }
+
+            unsigned char* data() const {
+                assert(m_data);
+                return m_data;
+            }
+
+            TMember& operator*() const {
+                assert(m_data);
+                assert(m_data != m_end);
+                return *reinterpret_cast<TMember*>(m_data);
+            }
+
+            TMember* operator->() const {
+                assert(m_data);
+                assert(m_data != m_end);
+                return reinterpret_cast<TMember*>(m_data);
+            }
+
+            explicit operator bool() const {
+                return m_data != nullptr;
+            }
+
+            template <typename TChar, typename TTraits>
+            friend std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const ItemIterator<TMember>& iter) {
+                return out << static_cast<void*>(iter.m_data);
+            }
+
+        }; // class ItemIterator
+
+    } // namespace memory
+
+} // namespace osmium
+
+#endif // OSMIUM_ITEM_ITERATOR_HPP
diff --git a/contrib/libosmium/osmium/object_pointer_collection.hpp b/contrib/libosmium/osmium/object_pointer_collection.hpp
new file mode 100644
index 0000000..85566b6
--- /dev/null
+++ b/contrib/libosmium/osmium/object_pointer_collection.hpp
@@ -0,0 +1,112 @@
+#ifndef OSMIUM_OBJECT_POINTER_COLLECTION_HPP
+#define OSMIUM_OBJECT_POINTER_COLLECTION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <utility>
+#include <vector>
+
+#include <boost/iterator/indirect_iterator.hpp>
+
+#include <osmium/handler.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/object.hpp>
+
+// IWYU pragma: no_forward_declare osmium::OSMObject
+// IWYU pragma: no_forward_declare osmium::memory::Item
+
+namespace osmium {
+
+    /**
+     * A collection of pointers to OSM objects. The pointers can be easily
+     * and quickly sorted or otherwise manipulated, while the objects
+     * themselves or the buffers they are in, do not have to be changed.
+     *
+     * An iterator is provided that can iterate over the pointers but looks
+     * like it is iterating over the underlying OSM objects.
+     *
+     * This class implements the visitor pattern which makes it easy to
+     * populate the collection from a buffer of OSM objects:
+     *
+     *   osmium::ObjectPointerCollection objects;
+     *   osmium::memory::Buffer buffer = reader.read();
+     *   osmium::apply(buffer, objects);
+     *
+     */
+    class ObjectPointerCollection : public osmium::handler::Handler {
+
+        std::vector<osmium::OSMObject*> m_objects;
+
+    public:
+
+        typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::iterator, osmium::OSMObject> iterator;
+        typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::const_iterator, const osmium::OSMObject> const_iterator;
+
+        ObjectPointerCollection() noexcept :
+            m_objects() {
+        }
+
+        void osm_object(osmium::OSMObject& object) {
+            m_objects.push_back(&object);
+        }
+
+        /**
+         * Sort objects according to the given order functor.
+         */
+        template <typename TCompare>
+        void sort(TCompare&& compare) {
+            std::sort(m_objects.begin(), m_objects.end(), std::forward<TCompare>(compare));
+        }
+
+        iterator begin() {
+            return iterator { m_objects.begin() };
+        }
+
+        iterator end() {
+            return iterator { m_objects.end() };
+        }
+
+        const_iterator cbegin() const {
+            return const_iterator { m_objects.cbegin() };
+        }
+
+        const_iterator cend() const {
+            return const_iterator { m_objects.cend() };
+        }
+
+    }; // class ObjectPointerCollection
+
+} // namespace osmium
+
+#endif // OSMIUM_OBJECT_POINTER_COLLECTION_HPP
diff --git a/contrib/libosmium/osmium/osm.hpp b/contrib/libosmium/osmium/osm.hpp
new file mode 100644
index 0000000..e92d9b8
--- /dev/null
+++ b/contrib/libosmium/osmium/osm.hpp
@@ -0,0 +1,48 @@
+#ifndef OSMIUM_OSM_HPP
+#define OSMIUM_OSM_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/osm/node.hpp> // IWYU pragma: export
+#include <osmium/osm/way.hpp> // IWYU pragma: export
+#include <osmium/osm/relation.hpp> // IWYU pragma: export
+#include <osmium/osm/area.hpp> // IWYU pragma: export
+#include <osmium/osm/changeset.hpp> // IWYU pragma: export
+
+/**
+ * @brief Namespace for everything in the Osmium library.
+ */
+namespace osmium {
+} // namespace osmium
+
+#endif // OSMIUM_OSM_HPP
diff --git a/contrib/libosmium/osmium/osm/area.hpp b/contrib/libosmium/osmium/osm/area.hpp
new file mode 100644
index 0000000..4e11c8b
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/area.hpp
@@ -0,0 +1,215 @@
+#ifndef OSMIUM_OSM_AREA_HPP
+#define OSMIUM_OSM_AREA_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstdlib>
+#include <utility>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/node_ref_list.hpp>
+
+namespace osmium {
+
+    namespace builder {
+        template <class T> class ObjectBuilder;
+    }
+
+    /**
+     * An outer ring of an Area.
+     */
+    class OuterRing : public NodeRefList {
+
+    public:
+
+        static constexpr osmium::item_type itemtype = osmium::item_type::outer_ring;
+
+        OuterRing():
+            NodeRefList(itemtype) {
+        }
+
+    }; // class OuterRing
+
+    static_assert(sizeof(OuterRing) % osmium::memory::align_bytes == 0, "Class osmium::OuterRing has wrong size to be aligned properly!");
+
+    /**
+     * An inner ring of an Area.
+     */
+    class InnerRing : public NodeRefList {
+
+    public:
+
+        static constexpr osmium::item_type itemtype = osmium::item_type::inner_ring;
+
+        InnerRing():
+            NodeRefList(itemtype) {
+        }
+
+    }; // class InnerRing
+
+    static_assert(sizeof(InnerRing) % osmium::memory::align_bytes == 0, "Class osmium::InnerRing has wrong size to be aligned properly!");
+
+    /**
+     * Convert way or (multipolygon) relation id into unique area id.
+     *
+     * @param id Id of a way or relation
+     * @param type Type of object (way or relation)
+     * @returns Area id
+     */
+    inline osmium::object_id_type object_id_to_area_id(osmium::object_id_type id, osmium::item_type type) noexcept {
+        osmium::object_id_type area_id = std::abs(id) * 2;
+        if (type == osmium::item_type::relation) {
+            ++area_id;
+        }
+        return id < 0 ? -area_id : area_id;
+    }
+
+    /**
+     * Convert area id into id of the way or relation it was created from.
+     *
+     * @param id Area id
+     * @returns Way or Relation id.
+     */
+    inline osmium::object_id_type area_id_to_object_id(osmium::object_id_type id) noexcept {
+        return id / 2;
+    }
+
+    /**
+     * An OSM area created out of a closed way or a multipolygon relation.
+     */
+    class Area : public OSMObject {
+
+        friend class osmium::builder::ObjectBuilder<osmium::Area>;
+
+        Area() :
+            OSMObject(sizeof(Area), osmium::item_type::area) {
+        }
+
+    public:
+
+        static constexpr osmium::item_type itemtype = osmium::item_type::area;
+
+        /**
+         * Was this area created from a way? (In contrast to areas
+         * created from a relation and their members.)
+         */
+        bool from_way() const noexcept {
+            return (positive_id() & 0x1) == 0;
+        }
+
+        /**
+         * Return the Id of the way or relation this area was created from.
+         */
+        osmium::object_id_type orig_id() const noexcept {
+            return osmium::area_id_to_object_id(id());
+        }
+
+        /**
+         * Count the number of outer and inner rings of this area.
+         *
+         * @returns Pair (number outer rings, number inner rings)
+         */
+        std::pair<int, int> num_rings() const {
+            std::pair<int, int> counter { 0, 0 };
+
+            for (auto it = cbegin(); it != cend(); ++it) {
+                switch (it->type()) {
+                    case osmium::item_type::outer_ring:
+                        ++counter.first;
+                        break;
+                    case osmium::item_type::inner_ring:
+                        ++counter.second;
+                        break;
+                    case osmium::item_type::tag_list:
+                        // ignore tags
+                        break;
+                    case osmium::item_type::undefined:
+                    case osmium::item_type::node:
+                    case osmium::item_type::way:
+                    case osmium::item_type::relation:
+                    case osmium::item_type::area:
+                    case osmium::item_type::changeset:
+                    case osmium::item_type::way_node_list:
+                    case osmium::item_type::relation_member_list:
+                    case osmium::item_type::relation_member_list_with_full_members:
+                    case osmium::item_type::changeset_discussion:
+                        assert(false && "Children of Area can only be outer/inner_ring and tag_list.");
+                        break;
+                }
+            }
+
+            return counter;
+        }
+
+        /**
+         * Check whether this area is a multipolygon, ie. whether it has more
+         * than one outer ring?
+         */
+        bool is_multipolygon() const {
+            return num_rings().first > 1;
+        }
+
+        /**
+         * Get iterator for iterating over all inner rings in a specified outer
+         * ring.
+         *
+         * @param it Iterator specifying outer ring.
+         * @returns Iterator to first inner ring in specified outer ring.
+         */
+        osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cbegin(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
+            return it.cast<const osmium::InnerRing>();
+        }
+
+        /**
+         * Get iterator for iterating over all inner rings in a specified outer
+         * ring.
+         *
+         * @param it Iterator specifying outer ring.
+         * @returns Iterator one past last inner ring in specified outer ring.
+         */
+        osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cend(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
+            return std::next(it).cast<const osmium::InnerRing>();
+        }
+
+    }; // class Area
+
+    static_assert(sizeof(Area) % osmium::memory::align_bytes == 0, "Class osmium::Area has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_AREA_HPP
diff --git a/contrib/libosmium/osmium/osm/box.hpp b/contrib/libosmium/osmium/osm/box.hpp
new file mode 100644
index 0000000..631f919
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/box.hpp
@@ -0,0 +1,250 @@
+#ifndef OSMIUM_OSM_BOX_HPP
+#define OSMIUM_OSM_BOX_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <iosfwd>
+
+#include <osmium/util/compatibility.hpp>
+#include <osmium/osm/location.hpp>
+
+namespace osmium {
+
+    /**
+     * Bounding box. A box is defined by two locations (bottom left location
+     * and top right location) or, alternatively by four coordinates (minx,
+     * miny, maxx, and maxy). If both locations are undefined, the box is
+     * undefined, too.
+     */
+    class Box {
+
+        osmium::Location m_bottom_left;
+        osmium::Location m_top_right;
+
+    public:
+
+        /**
+         * Create undefined Box. Use the extend() function
+         * to add actual bounds.
+         */
+        constexpr Box() noexcept :
+            m_bottom_left(),
+            m_top_right() {
+        }
+
+        /**
+         * Create box from minimum and maximum coordinates.
+         *
+         * @pre @code minx <= maxx && miny <= maxy @endcode
+         */
+        Box(double minx, double miny, double maxx, double maxy) :
+            m_bottom_left(minx, miny),
+            m_top_right(maxx, maxy) {
+            assert(minx <= maxx && miny <= maxy);
+        }
+
+        /**
+         * Create box from bottom left and top right locations.
+         *
+         * @pre Either both locations must be defined or neither.
+         * @pre If both locations are defined, the
+         *      bottom left location must actually be to the left and below
+         *      the top right location. Same coordinates for bottom/top or
+         *      left/right are also okay.
+         */
+        Box(const osmium::Location& bottom_left, const osmium::Location& top_right) :
+            m_bottom_left(bottom_left),
+            m_top_right(top_right) {
+            assert(
+                (!!bottom_left && !!top_right) ||
+                (bottom_left.x() <= top_right.x() && bottom_left.y() <= top_right.y())
+            );
+        }
+
+        Box(const Box&) = default;
+        Box(Box&&) = default;
+        Box& operator=(const Box&) = default;
+        Box& operator=(Box&&) = default;
+        ~Box() = default;
+
+        /**
+         * Extend this bounding box by the specified location. If the
+         * location is undefined, the bounding box is unchanged. If
+         * the box is undefined it will only contain the location after
+         * this call.
+         *
+         * @param location The location we want to extend the box by.
+         * @returns A reference to this box.
+         */
+        Box& extend(const Location& location) noexcept {
+            if (location) {
+                if (m_bottom_left) {
+                    if (location.x() < m_bottom_left.x()) {
+                        m_bottom_left.set_x(location.x());
+                    }
+                    if (location.x() > m_top_right.x()) {
+                        m_top_right.set_x(location.x());
+                    }
+                    if (location.y() < m_bottom_left.y()) {
+                        m_bottom_left.set_y(location.y());
+                    }
+                    if (location.y() > m_top_right.y()) {
+                        m_top_right.set_y(location.y());
+                    }
+                } else {
+                    m_bottom_left = location;
+                    m_top_right = location;
+                }
+            }
+            return *this;
+        }
+
+        /**
+         * Extend this bounding box by the specified box. If the
+         * specified box is undefined, the bounding box is unchanged.
+         *
+         * @param box The box to extend by.
+         * @returns A reference to this box.
+         */
+        Box& extend(const Box& box) noexcept {
+            extend(box.bottom_left());
+            extend(box.top_right());
+            return *this;
+        }
+
+        /**
+         * Box is defined, ie. contains defined locations.
+         */
+        explicit constexpr operator bool() const noexcept {
+            return static_cast<bool>(m_bottom_left);
+        }
+
+        /**
+         * Box is valid, ie. defined and inside usual bounds
+         * (-180<=lon<=180, -90<=lat<=90).
+         */
+        OSMIUM_CONSTEXPR bool valid() const noexcept {
+            return bottom_left().valid() && top_right().valid();
+        }
+
+        /**
+         * Access bottom-left location.
+         */
+        OSMIUM_CONSTEXPR Location bottom_left() const noexcept {
+            return m_bottom_left;
+        }
+
+        /**
+         * Access bottom-left location.
+         */
+        Location& bottom_left() noexcept {
+            return m_bottom_left;
+        }
+
+        /**
+         * Access top-right location.
+         */
+        OSMIUM_CONSTEXPR Location top_right() const noexcept {
+            return m_top_right;
+        }
+
+        /**
+         * Access top-right location.
+         */
+        Location& top_right() noexcept {
+            return m_top_right;
+        }
+
+        /**
+         * Check whether the location is inside the box.
+         *
+         * @pre Location must be defined.
+         * @pre Box must be defined.
+         */
+        bool contains(const osmium::Location& location) const noexcept {
+            assert(bottom_left());
+            assert(top_right());
+            assert(location);
+            return location.x() >= bottom_left().x() && location.y() >= bottom_left().y() &&
+                   location.x() <= top_right().x() && location.y() <= top_right().y();
+        }
+
+        /**
+         * Calculate size of the box in square degrees.
+         *
+         * @throws osmium::invalid_location unless all coordinates are valid.
+         */
+        double size() const {
+            return (m_top_right.lon() - m_bottom_left.lon()) *
+                   (m_top_right.lat() - m_bottom_left.lat());
+        }
+
+    }; // class Box
+
+    /**
+     * Boxes are equal if both locations are equal. Undefined boxes will
+     * compare equal.
+     */
+    inline OSMIUM_CONSTEXPR bool operator==(const Box& lhs, const Box& rhs) noexcept {
+        return lhs.bottom_left() == rhs.bottom_left() &&
+               lhs.top_right() == rhs.top_right();
+    }
+
+    /**
+     * Output a box to a stream. The format is "(LON, LAT, LON, LAT)" or
+     * "(undefined)" if the box is undefined.
+     *
+     * @returns Reference to basic_ostream given as first parameter.
+     */
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Box& box) {
+        if (box) {
+            out << '('
+                << box.bottom_left().lon()
+                << ','
+                << box.bottom_left().lat()
+                << ','
+                << box.top_right().lon()
+                << ','
+                << box.top_right().lat()
+                << ')';
+        } else {
+            out << "(undefined)";
+        }
+        return out;
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_BOX_HPP
diff --git a/contrib/libosmium/osmium/osm/changeset.hpp b/contrib/libosmium/osmium/osm/changeset.hpp
new file mode 100644
index 0000000..051b525
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/changeset.hpp
@@ -0,0 +1,458 @@
+#ifndef OSMIUM_OSM_CHANGESET_HPP
+#define OSMIUM_OSM_CHANGESET_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstring>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/entity.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/types_from_string.hpp>
+
+namespace osmium {
+
+    namespace builder {
+        class ChangesetDiscussionBuilder;
+        template <typename T> class ObjectBuilder;
+    }
+
+    class Changeset;
+
+    class ChangesetComment : public osmium::memory::detail::ItemHelper {
+
+        friend class osmium::builder::ChangesetDiscussionBuilder;
+
+        osmium::Timestamp m_date;
+        osmium::user_id_type m_uid {0};
+        string_size_type m_user_size;
+        string_size_type m_text_size;
+
+        ChangesetComment(const ChangesetComment&) = delete;
+        ChangesetComment(ChangesetComment&&) = delete;
+
+        ChangesetComment& operator=(const ChangesetComment&) = delete;
+        ChangesetComment& operator=(ChangesetComment&&) = delete;
+
+        unsigned char* endpos() {
+            return data() + osmium::memory::padded_length(sizeof(ChangesetComment) + m_user_size + m_text_size);
+        }
+
+        const unsigned char* endpos() const {
+            return data() + osmium::memory::padded_length(sizeof(ChangesetComment) + m_user_size + m_text_size);
+        }
+
+        template <typename TMember>
+        friend class osmium::memory::CollectionIterator;
+
+        unsigned char* next() {
+            return endpos();
+        }
+
+        unsigned const char* next() const {
+            return endpos();
+        }
+
+        void set_user_size(string_size_type size) noexcept {
+            m_user_size = size;
+        }
+
+        void set_text_size(string_size_type size) noexcept {
+            m_text_size = size;
+        }
+
+    public:
+
+        static constexpr item_type collection_type = item_type::changeset_discussion;
+
+        ChangesetComment(osmium::Timestamp date, osmium::user_id_type uid) noexcept :
+            m_date(date),
+            m_uid(uid),
+            m_user_size(0),
+            m_text_size(0) {
+        }
+
+        osmium::Timestamp date() const noexcept {
+            return m_date;
+        }
+
+        osmium::user_id_type uid() const noexcept {
+            return m_uid;
+        }
+
+        const char* user() const noexcept {
+            return reinterpret_cast<const char*>(data() + sizeof(ChangesetComment));
+        }
+
+        const char* text() const noexcept {
+            return reinterpret_cast<const char*>(data() + sizeof(ChangesetComment) + m_user_size);
+        }
+
+    }; // class ChangesetComment
+
+    class ChangesetDiscussion : public osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion> {
+
+        friend class osmium::builder::ObjectBuilder<osmium::Changeset>;
+
+    public:
+
+        typedef size_t size_type;
+
+        ChangesetDiscussion() :
+            osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion>() {
+        }
+
+        size_type size() const noexcept {
+            return static_cast<size_type>(std::distance(begin(), end()));
+        }
+
+    }; // class ChangesetDiscussion
+
+    static_assert(sizeof(ChangesetDiscussion) % osmium::memory::align_bytes == 0, "Class osmium::ChangesetDiscussion has wrong size to be aligned properly!");
+
+    /**
+     * \brief An OSM Changeset, a group of changes made by a single user over
+     *        a short period of time.
+     *
+     * You can not create Changeset objects directly. Use the ChangesetBuilder
+     * class to create Changesets in a Buffer.
+     */
+    class Changeset : public osmium::OSMEntity {
+
+        friend class osmium::builder::ObjectBuilder<osmium::Changeset>;
+
+        osmium::Box       m_bounds;
+        osmium::Timestamp m_created_at;
+        osmium::Timestamp m_closed_at;
+        changeset_id_type m_id {0};
+        num_changes_type  m_num_changes {0};
+        num_comments_type m_num_comments {0};
+        user_id_type      m_uid {0};
+        string_size_type  m_user_size;
+        int16_t           m_padding1 {0};
+        int32_t           m_padding2 {0};
+
+        Changeset() :
+            OSMEntity(sizeof(Changeset), osmium::item_type::changeset) {
+        }
+
+        void set_user_size(string_size_type size) {
+            m_user_size = size;
+        }
+
+        unsigned char* subitems_position() {
+            return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size);
+        }
+
+        const unsigned char* subitems_position() const {
+            return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size);
+        }
+
+    public:
+
+        /// Get ID of this changeset
+        changeset_id_type id() const noexcept {
+            return m_id;
+        }
+
+        /**
+         * Set ID of this changeset
+         *
+         * @param id The id.
+         * @returns Reference to changeset to make calls chainable.
+         */
+        Changeset& set_id(changeset_id_type id) noexcept {
+            m_id = id;
+            return *this;
+        }
+
+        /**
+         * Set ID of this changeset.
+         *
+         * @param id The id.
+         * @returns Reference to object to make calls chainable.
+         */
+        Changeset& set_id(const char* id) {
+            return set_id(osmium::string_to_changeset_id(id));
+        }
+
+        /// Get user id.
+        user_id_type uid() const noexcept {
+            return m_uid;
+        }
+
+        /**
+         * Set user id.
+         *
+         * @param uid The user id.
+         * @returns Reference to changeset to make calls chainable.
+         */
+        Changeset& set_uid(user_id_type uid) noexcept {
+            m_uid = uid;
+            return *this;
+        }
+
+        /**
+         * Set user id to given uid or to 0 (anonymous user) if the given
+         * uid is smaller than 0.
+         *
+         * @param uid The user id.
+         * @returns Reference to changeset to make calls chainable.
+         */
+        Changeset& set_uid_from_signed(signed_user_id_type uid) noexcept {
+            m_uid = uid < 0 ? 0 : static_cast<user_id_type>(uid);
+            return *this;
+        }
+
+        /**
+         * Set user id to given uid or to 0 (anonymous user) if the given
+         * uid is smaller than 0.
+         *
+         * @returns Reference to changeset to make calls chainable.
+         */
+        Changeset& set_uid(const char* uid) {
+            return set_uid_from_signed(string_to_user_id(uid));
+        }
+
+        /// Is this user anonymous?
+        bool user_is_anonymous() const noexcept {
+            return m_uid == 0;
+        }
+
+        /// Get timestamp when this changeset was created.
+        osmium::Timestamp created_at() const noexcept {
+            return m_created_at;
+        }
+
+        /**
+         * Get timestamp when this changeset was closed.
+         *
+         * @returns Timestamp. Will return the empty Timestamp when the
+         *          changeset is not yet closed.
+         */
+        osmium::Timestamp closed_at() const noexcept {
+            return m_closed_at;
+        }
+
+        /// Is this changeset open?
+        bool open() const noexcept {
+            return m_closed_at == osmium::Timestamp();
+        }
+
+        /// Is this changeset closed?
+        bool closed() const noexcept {
+            return !open();
+        }
+
+        /**
+         * Set the timestamp when this changeset was created.
+         *
+         * @param timestamp Timestamp
+         * @returns Reference to changeset to make calls chainable.
+         */
+        Changeset& set_created_at(const osmium::Timestamp& timestamp) {
+            m_created_at = timestamp;
+            return *this;
+        }
+
+        /**
+         * Set the timestamp when this changeset was closed.
+         *
+         * @param timestamp Timestamp
+         * @returns Reference to changeset to make calls chainable.
+         */
+        Changeset& set_closed_at(const osmium::Timestamp& timestamp) {
+            m_closed_at = timestamp;
+            return *this;
+        }
+
+        /// Get the number of changes in this changeset
+        num_changes_type num_changes() const noexcept {
+            return m_num_changes;
+        }
+
+        /// Set the number of changes in this changeset
+        Changeset& set_num_changes(num_changes_type num_changes) noexcept {
+            m_num_changes = num_changes;
+            return *this;
+        }
+
+        /// Set the number of changes in this changeset
+        Changeset& set_num_changes(const char* num_changes) {
+            return set_num_changes(osmium::string_to_num_changes(num_changes));
+        }
+
+        /// Get the number of comments in this changeset
+        num_comments_type num_comments() const noexcept {
+            return m_num_comments;
+        }
+
+        /// Set the number of comments in this changeset
+        Changeset& set_num_comments(num_comments_type num_comments) noexcept {
+            m_num_comments = num_comments;
+            return *this;
+        }
+
+        /// Set the number of comments in this changeset
+        Changeset& set_num_comments(const char* num_comments) {
+            return set_num_comments(osmium::string_to_num_comments(num_comments));
+        }
+
+        /**
+         * Get the bounding box of this changeset.
+         *
+         * @returns Bounding box. Can be empty.
+         */
+        osmium::Box& bounds() noexcept {
+            return m_bounds;
+        }
+
+        /**
+         * Get the bounding box of this changeset.
+         *
+         * @returns Bounding box. Can be empty.
+         */
+        const osmium::Box& bounds() const noexcept {
+            return m_bounds;
+        }
+
+        /// Get user name.
+        const char* user() const {
+            return reinterpret_cast<const char*>(data() + sizeof(Changeset));
+        }
+
+        /// Get the list of tags.
+        const TagList& tags() const {
+            return osmium::detail::subitem_of_type<const TagList>(cbegin(), cend());
+        }
+
+        /**
+         * Set named attribute.
+         *
+         * @param attr Name of the attribute (must be one of "id", "version",
+         *             "changeset", "timestamp", "uid", "visible")
+         * @param value Value of the attribute
+         */
+        void set_attribute(const char* attr, const char* value) {
+            if (!strcmp(attr, "id")) {
+                set_id(value);
+            } else if (!strcmp(attr, "num_changes")) {
+                set_num_changes(value);
+            } else if (!strcmp(attr, "comments_count")) {
+                set_num_comments(value);
+            } else if (!strcmp(attr, "created_at")) {
+                set_created_at(osmium::Timestamp(value));
+            } else if (!strcmp(attr, "closed_at")) {
+                set_closed_at(osmium::Timestamp(value));
+            } else if (!strcmp(attr, "uid")) {
+                set_uid(value);
+            }
+        }
+
+        typedef osmium::memory::CollectionIterator<Item> iterator;
+        typedef osmium::memory::CollectionIterator<const Item> const_iterator;
+
+        iterator begin() {
+            return iterator(subitems_position());
+        }
+
+        iterator end() {
+            return iterator(data() + padded_size());
+        }
+
+        const_iterator cbegin() const {
+            return const_iterator(subitems_position());
+        }
+
+        const_iterator cend() const {
+            return const_iterator(data() + padded_size());
+        }
+
+        const_iterator begin() const {
+            return cbegin();
+        }
+
+        const_iterator end() const {
+            return cend();
+        }
+
+        ChangesetDiscussion& discussion() {
+            return osmium::detail::subitem_of_type<ChangesetDiscussion>(begin(), end());
+        }
+
+        const ChangesetDiscussion& discussion() const {
+            return osmium::detail::subitem_of_type<const ChangesetDiscussion>(cbegin(), cend());
+        }
+
+    }; // class Changeset
+
+    static_assert(sizeof(Changeset) % osmium::memory::align_bytes == 0, "Class osmium::Changeset has wrong size to be aligned properly!");
+
+    /**
+     * Changesets are equal if their IDs are equal.
+     */
+    inline bool operator==(const Changeset& lhs, const Changeset& rhs) {
+        return lhs.id() == rhs.id();
+    }
+
+    inline bool operator!=(const Changeset& lhs, const Changeset& rhs) {
+        return ! (lhs == rhs);
+    }
+
+    /**
+     * Changesets can be ordered by id.
+     */
+    inline bool operator<(const Changeset& lhs, const Changeset& rhs) {
+        return lhs.id() < rhs.id();
+    }
+
+    inline bool operator>(const Changeset& lhs, const Changeset& rhs) {
+        return rhs < lhs;
+    }
+
+    inline bool operator<=(const Changeset& lhs, const Changeset& rhs) {
+        return ! (rhs < lhs);
+    }
+
+    inline bool operator>=(const Changeset& lhs, const Changeset& rhs) {
+        return ! (lhs < rhs);
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_CHANGESET_HPP
diff --git a/contrib/libosmium/osmium/osm/crc.hpp b/contrib/libosmium/osmium/osm/crc.hpp
new file mode 100644
index 0000000..309f50a
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/crc.hpp
@@ -0,0 +1,242 @@
+#ifndef OSMIUM_OSM_CRC_HPP
+#define OSMIUM_OSM_CRC_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdint>
+
+#include <osmium/osm/area.hpp>
+#include <osmium/osm/changeset.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/node_ref_list.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/util/endian.hpp>
+
+namespace osmium {
+
+    namespace util {
+
+        inline uint16_t byte_swap_16(uint16_t value) noexcept {
+# if defined(__GNUC__) || defined(__clang__)
+            return __builtin_bswap16(value);
+# else
+            return (value >> 8) | (value << 8);
+# endif
+        }
+
+        inline uint32_t byte_swap_32(uint32_t value) noexcept {
+# if defined(__GNUC__) || defined(__clang__)
+            return __builtin_bswap32(value);
+# else
+            return  (value >> 24) |
+                   ((value >>  8) & 0x0000FF00) |
+                   ((value <<  8) & 0x00FF0000) |
+                    (value << 24);
+# endif
+        }
+
+        inline uint64_t byte_swap_64(uint64_t value) noexcept {
+# if defined(__GNUC__) || defined(__clang__)
+            return __builtin_bswap64(value);
+# else
+            uint64_t val1 = byte_swap_32(value & 0xFFFFFFFF);
+            uint64_t val2 = byte_swap_32(value >> 32);
+            return (val1 << 32) | val2;
+# endif
+        }
+
+    }
+
+    template <typename TCRC>
+    class CRC {
+
+        TCRC m_crc;
+
+    public:
+
+        TCRC& operator()() {
+            return m_crc;
+        }
+
+        const TCRC& operator()() const {
+            return m_crc;
+        }
+
+        void update_bool(const bool value) {
+            m_crc.process_byte(value);
+        }
+
+        void update_int8(const uint8_t value) {
+            m_crc.process_byte(value);
+        }
+
+        void update_int16(const uint16_t value) {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+            m_crc.process_bytes(&value, sizeof(uint16_t));
+#else
+            uint16_t v = osmium::util::byte_swap_16(value);
+            m_crc.process_bytes(&v, sizeof(uint16_t));
+#endif
+        }
+
+        void update_int32(const uint32_t value) {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+            m_crc.process_bytes(&value, sizeof(uint32_t));
+#else
+            uint32_t v = osmium::util::byte_swap_32(value);
+            m_crc.process_bytes(&v, sizeof(uint32_t));
+#endif
+        }
+
+        void update_int64(const uint64_t value) {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+            m_crc.process_bytes(&value, sizeof(uint64_t));
+#else
+            uint64_t v = osmium::util::byte_swap_64(value);
+            m_crc.process_bytes(&v, sizeof(uint64_t));
+#endif
+        }
+
+        void update_string(const char* str) {
+            while (*str) {
+                m_crc.process_byte(*str++);
+            }
+        }
+
+        void update(const Timestamp& timestamp) {
+            update_int32(uint32_t(timestamp));
+        }
+
+        void update(const osmium::Location& location) {
+            update_int32(location.x());
+            update_int32(location.y());
+        }
+
+        void update(const osmium::Box& box) {
+            update(box.bottom_left());
+            update(box.top_right());
+        }
+
+        void update(const NodeRef& node_ref) {
+            update_int64(node_ref.ref());
+        }
+
+        void update(const NodeRefList& node_refs) {
+            for (const NodeRef& node_ref : node_refs) {
+                update(node_ref);
+            }
+        }
+
+        void update(const TagList& tags) {
+            for (const Tag& tag : tags) {
+                update_string(tag.key());
+                update_string(tag.value());
+            }
+        }
+
+        void update(const osmium::RelationMember& member) {
+            update_int64(member.ref());
+            update_int16(uint16_t(member.type()));
+            update_string(member.role());
+        }
+
+        void update(const osmium::RelationMemberList& members) {
+            for (const RelationMember& member : members) {
+                update(member);
+            }
+        }
+
+        void update(const osmium::OSMObject& object) {
+            update_int64(object.id());
+            update_bool(object.visible());
+            update_int32(object.version());
+            update(object.timestamp());
+            update_int32(object.uid());
+            update_string(object.user());
+            update(object.tags());
+        }
+
+        void update(const osmium::Node& node) {
+            update(static_cast<const osmium::OSMObject&>(node));
+            update(node.location());
+        }
+
+        void update(const osmium::Way& way) {
+            update(static_cast<const osmium::OSMObject&>(way));
+            update(way.nodes());
+        }
+
+        void update(const osmium::Relation& relation) {
+            update(static_cast<const osmium::OSMObject&>(relation));
+            update(relation.members());
+        }
+
+        void update(const osmium::Area& area) {
+            update(static_cast<const osmium::OSMObject&>(area));
+            for (auto it = area.cbegin(); it != area.cend(); ++it) {
+                if (it->type() == osmium::item_type::outer_ring ||
+                    it->type() == osmium::item_type::inner_ring) {
+                    update(static_cast<const osmium::NodeRefList&>(*it));
+                }
+            }
+        }
+
+        void update(const osmium::ChangesetDiscussion& discussion) {
+            for (const auto& comment : discussion) {
+                update(comment.date());
+                update_int32(comment.uid());
+                update_string(comment.user());
+                update_string(comment.text());
+            }
+        }
+
+        void update(const osmium::Changeset& changeset) {
+            update_int64(changeset.id());
+            update(changeset.created_at());
+            update(changeset.closed_at());
+            update(changeset.bounds());
+            update_int32(changeset.num_changes());
+            update_int32(changeset.num_comments());
+            update_int32(changeset.uid());
+            update_string(changeset.user());
+            update(changeset.tags());
+            update(changeset.discussion());
+        }
+
+    }; // class CRC
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_CRC
diff --git a/contrib/libosmium/osmium/osm/diff_object.hpp b/contrib/libosmium/osmium/osm/diff_object.hpp
new file mode 100644
index 0000000..96e07bc
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/diff_object.hpp
@@ -0,0 +1,180 @@
+#ifndef OSMIUM_OSM_DIFF_OBJECT_HPP
+#define OSMIUM_OSM_DIFF_OBJECT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/fwd.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    class DiffObject {
+
+    protected:
+
+        osmium::OSMObject* m_prev;
+        osmium::OSMObject* m_curr;
+        osmium::OSMObject* m_next;
+
+    public:
+
+        DiffObject() noexcept :
+            m_prev(nullptr),
+            m_curr(nullptr),
+            m_next(nullptr) {
+        }
+
+        explicit DiffObject(osmium::OSMObject& prev, osmium::OSMObject& curr, osmium::OSMObject& next) noexcept :
+            m_prev(&prev),
+            m_curr(&curr),
+            m_next(&next) {
+        }
+
+        DiffObject(const DiffObject&) = default;
+        DiffObject& operator=(const DiffObject&) = default;
+
+        DiffObject(DiffObject&&) = default;
+        DiffObject& operator=(DiffObject&&) = default;
+
+        const osmium::OSMObject& prev() const noexcept {
+            return *m_prev;
+        }
+
+        const osmium::OSMObject& curr() const noexcept {
+            return *m_curr;
+        }
+
+        const osmium::OSMObject& next() const noexcept {
+            return *m_next;
+        }
+
+        bool first() const noexcept {
+            return m_prev == m_curr;
+        }
+
+        bool last() const noexcept {
+            return m_curr == m_next;
+        }
+
+        osmium::item_type type() const noexcept {
+            return m_curr->type();
+        }
+
+        osmium::object_id_type id() const noexcept {
+            return m_curr->id();
+        }
+
+        osmium::object_version_type version() const noexcept {
+            return m_curr->version();
+        }
+
+        osmium::changeset_id_type changeset() const noexcept {
+            return m_curr->changeset();
+        }
+
+        const osmium::Timestamp start_time() const noexcept {
+            return m_curr->timestamp();
+        }
+
+        /**
+         * Return the timestamp when the current version of the object is
+         * not valid any more, ie the time when the next version of the object
+         * is valid. If this is the last version of the object, this will
+         * return a special "end of time" timestamp that is guaranteed to
+         * be larger than any normal timestamp.
+         */
+        const osmium::Timestamp end_time() const noexcept {
+            return last() ? osmium::end_of_time() : m_next->timestamp();
+        }
+
+        /**
+         * Current object version is valid between time "from" (inclusive) and
+         * time "to" (not inclusive).
+         *
+         * This is a bit more complex than you'd think, because we have to
+         * handle the case properly where the start_time() == end_time().
+         */
+        bool is_between(const osmium::Timestamp& from, const osmium::Timestamp& to) const noexcept {
+            return start_time() < to &&
+                   ((start_time() != end_time() && end_time() >  from) ||
+                    (start_time() == end_time() && end_time() >= from));
+        }
+
+        /**
+         * Current object version is visible at the given timestamp.
+         */
+        bool is_visible_at(const osmium::Timestamp& timestamp) const noexcept {
+            return start_time() <= timestamp && end_time() > timestamp && m_curr->visible();
+        }
+
+    }; // class DiffObject
+
+    template <typename T>
+    class DiffObjectDerived : public DiffObject {
+
+    public:
+
+        DiffObjectDerived(T& prev, T& curr, T& next) noexcept :
+            DiffObject(prev, curr, next) {
+        }
+
+        DiffObjectDerived(const DiffObjectDerived&) = default;
+        DiffObjectDerived& operator=(const DiffObjectDerived&) = default;
+
+        DiffObjectDerived(DiffObjectDerived&&) = default;
+        DiffObjectDerived& operator=(DiffObjectDerived&&) = default;
+
+        const T& prev() const noexcept {
+            return *static_cast<const T*>(m_prev);
+        }
+
+        const T& curr() const noexcept {
+            return *static_cast<const T*>(m_curr);
+        }
+
+        const T& next() const noexcept {
+            return *static_cast<const T*>(m_next);
+        }
+
+    }; // class DiffObjectDerived
+
+    typedef DiffObjectDerived<osmium::Node>     DiffNode;
+    typedef DiffObjectDerived<osmium::Way>      DiffWay;
+    typedef DiffObjectDerived<osmium::Relation> DiffRelation;
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_DIFF_OBJECT_HPP
diff --git a/contrib/libosmium/osmium/osm/entity.hpp b/contrib/libosmium/osmium/osm/entity.hpp
new file mode 100644
index 0000000..c7f7055
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/entity.hpp
@@ -0,0 +1,80 @@
+#ifndef OSMIUM_OSM_ENTITY_HPP
+#define OSMIUM_OSM_ENTITY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+    namespace detail {
+
+        template <typename TSubitem, typename TIter>
+        inline TSubitem& subitem_of_type(TIter it, TIter end) {
+            for (; it != end; ++it) {
+                if (it->type() == TSubitem::itemtype) {
+                    return reinterpret_cast<TSubitem&>(*it);
+                }
+            }
+
+            // If no subitem of the TSubitem type was found,
+            // return a default constructed one.
+            static TSubitem subitem;
+            return subitem;
+        }
+
+    } // namespace detail
+
+    /**
+     * \brief OSMEntity is the abstract base class for the OSMObject and
+     *        Changeset classes.
+     */
+    class OSMEntity : public osmium::memory::Item {
+
+    public:
+
+        explicit OSMEntity(osmium::memory::item_size_type size, osmium::item_type type) :
+            Item(size, type) {
+        }
+
+        bool type_is_in(osmium::osm_entity_bits::type entity_bits) const {
+            return (osm_entity_bits::from_item_type(type()) & entity_bits) != 0;
+        }
+
+    }; // class OSMEntity
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_ENTITY_HPP
diff --git a/contrib/libosmium/osmium/osm/entity_bits.hpp b/contrib/libosmium/osmium/osm/entity_bits.hpp
new file mode 100644
index 0000000..1c1cb80
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/entity_bits.hpp
@@ -0,0 +1,105 @@
+#ifndef OSMIUM_OSM_ENTITY_BITS_HPP
+#define OSMIUM_OSM_ENTITY_BITS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Bitfield for OSM entity types.
+     */
+    namespace osm_entity_bits {
+
+        /**
+         * Describes zero or more OSM entities.
+         *
+         * Usage:
+         *
+         * @code{.cpp}
+         * osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::node | osmium::osm_entity_bits::way;
+         *
+         * entities |= osmium::osm_entity_bits::relation;
+         *
+         * assert(entities & osmium::osm_entity_bits::object);
+         *
+         * assert(! (entities & osmium::osm_entity_bits::changeset));
+         * @endcode
+         */
+        enum type : unsigned char {
+
+            nothing    = 0x00,
+            node       = 0x01,
+            way        = 0x02,
+            relation   = 0x04,
+            nwr        = 0x07, ///< node, way, or relation object
+            area       = 0x08,
+            nwra       = 0x0f, ///< node, way, relation, or area object
+            object     = 0x0f, ///< node, way, relation, or area object
+            changeset  = 0x10,
+            all        = 0x1f  ///< object or changeset
+
+        }; // enum type
+
+        inline type operator|(const type lhs, const type rhs) noexcept {
+            return static_cast<type>(static_cast<int>(lhs) | static_cast<int> (rhs));
+        }
+
+        inline type& operator|=(type& lhs, const type rhs) noexcept {
+            lhs = lhs | rhs;
+            return lhs;
+        }
+
+        inline type operator&(const type lhs, const type rhs) noexcept {
+            return static_cast<type>(static_cast<int>(lhs) & static_cast<int> (rhs));
+        }
+
+        inline type operator~(const type value) noexcept {
+            return static_cast<type>(~static_cast<int>(value));
+        }
+
+        inline type operator&=(type& lhs, const type rhs) noexcept {
+            lhs = lhs & rhs;
+            return lhs;
+        }
+
+        inline type from_item_type(osmium::item_type item_type) noexcept {
+            return static_cast<osmium::osm_entity_bits::type>(0x1 << (static_cast<uint16_t>(item_type) - 1));
+        }
+
+    } // namespace osm_entity_bits
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_ENTITY_BITS_HPP
diff --git a/contrib/libosmium/osmium/osm/item_type.hpp b/contrib/libosmium/osmium/osm/item_type.hpp
new file mode 100644
index 0000000..d8f5296
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/item_type.hpp
@@ -0,0 +1,200 @@
+#ifndef OSMIUM_OSM_ITEM_TYPE_HPP
+#define OSMIUM_OSM_ITEM_TYPE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstdint> // IWYU pragma: keep
+#include <iosfwd>
+#include <stdexcept>
+
+namespace osmium {
+
+    enum class item_type : uint16_t {
+
+        undefined                              = 0x00,
+        node                                   = 0x01,
+        way                                    = 0x02,
+        relation                               = 0x03,
+        area                                   = 0x04,
+        changeset                              = 0x05,
+        tag_list                               = 0x11,
+        way_node_list                          = 0x12,
+        relation_member_list                   = 0x13,
+        relation_member_list_with_full_members = 0x23,
+        outer_ring                             = 0x40,
+        inner_ring                             = 0x41,
+        changeset_discussion                   = 0x80
+
+    }; // enum class item_type
+
+    /**
+     * Return item_type for index:
+     * 0 -> node, 1 -> way, 2 -> relation
+     */
+    inline item_type nwr_index_to_item_type(unsigned int i) noexcept {
+        assert(i <= 2);
+        return item_type(i+1);
+    }
+
+    /**
+     * Return index for item_type:
+     * node -> 0, way -> 1, relation -> 2
+     */
+    inline unsigned int item_type_to_nwr_index(item_type type) noexcept {
+        unsigned int i = static_cast<unsigned int>(type);
+        assert(i >= 1 && i <= 3);
+        return i - 1;
+    }
+
+    inline item_type char_to_item_type(const char c) noexcept {
+        switch (c) {
+            case 'X':
+                return item_type::undefined;
+            case 'n':
+                return item_type::node;
+            case 'w':
+                return item_type::way;
+            case 'r':
+                return item_type::relation;
+            case 'a':
+                return item_type::area;
+            case 'c':
+                return item_type::changeset;
+            case 'T':
+                return item_type::tag_list;
+            case 'N':
+                return item_type::way_node_list;
+            case 'M':
+                return item_type::relation_member_list;
+            case 'F':
+                return item_type::relation_member_list_with_full_members;
+            case 'O':
+                return item_type::outer_ring;
+            case 'I':
+                return item_type::inner_ring;
+            case 'D':
+                return item_type::changeset_discussion;
+            default:
+                return item_type::undefined;
+        }
+    }
+
+// avoid g++ false positive
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+    inline char item_type_to_char(const item_type type) noexcept {
+        switch (type) {
+            case item_type::undefined:
+                return 'X';
+            case item_type::node:
+                return 'n';
+            case item_type::way:
+                return 'w';
+            case item_type::relation:
+                return 'r';
+            case item_type::area:
+                return 'a';
+            case item_type::changeset:
+                return 'c';
+            case item_type::tag_list:
+                return 'T';
+            case item_type::way_node_list:
+                return 'N';
+            case item_type::relation_member_list:
+                return 'M';
+            case item_type::relation_member_list_with_full_members:
+                return 'F';
+            case item_type::outer_ring:
+                return 'O';
+            case item_type::inner_ring:
+                return 'I';
+            case item_type::changeset_discussion:
+                return 'D';
+        }
+    }
+
+    inline const char* item_type_to_name(const item_type type) noexcept {
+        switch (type) {
+            case item_type::undefined:
+                return "undefined";
+            case item_type::node:
+                return "node";
+            case item_type::way:
+                return "way";
+            case item_type::relation:
+                return "relation";
+            case item_type::area:
+                return "area";
+            case item_type::changeset:
+                return "changeset";
+            case item_type::tag_list:
+                return "tag_list";
+            case item_type::way_node_list:
+                return "way_node_list";
+            case item_type::relation_member_list:
+                return "relation_member_list";
+            case item_type::relation_member_list_with_full_members:
+                return "relation_member_list_with_full_members";
+            case item_type::outer_ring:
+                return "outer_ring";
+            case item_type::inner_ring:
+                return "inner_ring";
+            case item_type::changeset_discussion:
+                return "changeset_discussion";
+        }
+    }
+#pragma GCC diagnostic pop
+
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const item_type item_type) {
+        return out << item_type_to_char(item_type);
+    }
+
+    /**
+     * This exception is thrown when a visitor encounters an unknown item type.
+     * Under usual circumstance this should not happen. If it does happen, it
+     * probably means the buffer contains different kinds of objects than were
+     * expected or that there is some kind of data corruption.
+     */
+    struct unknown_type : public std::runtime_error {
+
+        unknown_type() :
+            std::runtime_error("unknown item type") {
+        }
+
+    }; // struct unknown_type
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_ITEM_TYPE_HPP
diff --git a/contrib/libosmium/osmium/osm/location.hpp b/contrib/libosmium/osmium/osm/location.hpp
new file mode 100644
index 0000000..0d4fdc1
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/location.hpp
@@ -0,0 +1,285 @@
+#ifndef OSMIUM_OSM_LOCATION_HPP
+#define OSMIUM_OSM_LOCATION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cmath>
+#include <cstdint>
+#include <iosfwd>
+#include <stdexcept>
+#include <string>
+
+#include <iostream>
+
+#include <osmium/util/compatibility.hpp>
+#include <osmium/util/double.hpp>
+
+namespace osmium {
+
+    /**
+     * Exception signaling an invalid location, ie a location
+     * outside the -180 to 180 and -90 to 90 degree range.
+     */
+    struct invalid_location : public std::range_error {
+
+        invalid_location(const std::string& what) :
+            std::range_error(what) {
+        }
+
+        invalid_location(const char* what) :
+            std::range_error(what) {
+        }
+
+    }; // struct invalid_location
+
+    /**
+     * Locations define a place on earth.
+     *
+     * Locations are stored in 32 bit integers for the x and y
+     * coordinates, respectively. This gives you an accuracy of a few
+     * centimeters, good enough for OSM use. (The main OSM database
+     * uses the same scheme.)
+     *
+     * An undefined Location can be created by calling the constructor
+     * without parameters.
+     *
+     * Coordinates are never checked on whether they are inside bounds.
+     * Call valid() to check this.
+     */
+    class Location {
+
+        int32_t m_x;
+        int32_t m_y;
+
+    public:
+
+        // this value is used for a coordinate to mark it as undefined
+        // MSVC doesn't declare std::numeric_limits<int32_t>::max() as
+        // constexpr, so we hard code this for the time being.
+        // static constexpr int32_t undefined_coordinate = std::numeric_limits<int32_t>::max();
+        static constexpr int32_t undefined_coordinate = 2147483647;
+
+        static constexpr int coordinate_precision = 10000000;
+
+        static int32_t double_to_fix(const double c) noexcept {
+            return static_cast<int32_t>(std::round(c * coordinate_precision));
+        }
+
+        static OSMIUM_CONSTEXPR double fix_to_double(const int32_t c) noexcept {
+            return static_cast<double>(c) / coordinate_precision;
+        }
+
+        /**
+         * Create undefined Location.
+         */
+        explicit constexpr Location() noexcept :
+            m_x(undefined_coordinate),
+            m_y(undefined_coordinate) {
+        }
+
+        /**
+         * Create Location with given x and y coordinates.
+         * Note that these coordinates are coordinate_precision
+         * times larger than the real coordinates.
+         */
+        constexpr Location(const int32_t x, const int32_t y) noexcept :
+            m_x(x),
+            m_y(y) {
+        }
+
+        /**
+         * Create Location with given x and y coordinates.
+         * Note that these coordinates are coordinate_precision
+         * times larger than the real coordinates.
+         */
+        constexpr Location(const int64_t x, const int64_t y) noexcept :
+            m_x(static_cast<int32_t>(x)),
+            m_y(static_cast<int32_t>(y)) {
+        }
+
+        /**
+         * Create Location with given longitude and latitude.
+         */
+        Location(const double lon, const double lat) :
+            m_x(double_to_fix(lon)),
+            m_y(double_to_fix(lat)) {
+        }
+
+        Location(const Location&) = default;
+        Location(Location&&) = default;
+        Location& operator=(const Location&) = default;
+        Location& operator=(Location&&) = default;
+        ~Location() = default;
+
+        /**
+         * Check whether the coordinates of this location
+         * are defined.
+         */
+        explicit constexpr operator bool() const noexcept {
+            return m_x != undefined_coordinate && m_y != undefined_coordinate;
+        }
+
+        /**
+         * Check whether the coordinates are inside the
+         * usual bounds (-180<=lon<=180, -90<=lat<=90).
+         */
+        constexpr bool valid() const noexcept {
+            return m_x >= -180 * coordinate_precision
+                && m_x <=  180 * coordinate_precision
+                && m_y >=  -90 * coordinate_precision
+                && m_y <=   90 * coordinate_precision;
+        }
+
+        constexpr int32_t x() const noexcept {
+            return m_x;
+        }
+
+        constexpr int32_t y() const noexcept {
+            return m_y;
+        }
+
+        Location& set_x(const int32_t x) noexcept {
+            m_x = x;
+            return *this;
+        }
+
+        Location& set_y(const int32_t y) noexcept {
+            m_y = y;
+            return *this;
+        }
+
+        /**
+         * Get longitude.
+         *
+         * @throws invalid_location if the location is invalid
+         */
+        double lon() const {
+            if (!valid()) {
+                throw osmium::invalid_location("invalid location");
+            }
+            return fix_to_double(m_x);
+        }
+
+        /**
+         * Get longitude without checking the validity.
+         */
+        double lon_without_check() const {
+            return fix_to_double(m_x);
+        }
+
+        /**
+         * Get latitude.
+         *
+         * @throws invalid_location if the location is invalid
+         */
+        double lat() const {
+            if (!valid()) {
+                throw osmium::invalid_location("invalid location");
+            }
+            return fix_to_double(m_y);
+        }
+
+        /**
+         * Get latitude without checking the validity.
+         */
+        double lat_without_check() const {
+            return fix_to_double(m_y);
+        }
+
+        Location& set_lon(double lon) noexcept {
+            m_x = double_to_fix(lon);
+            return *this;
+        }
+
+        Location& set_lat(double lat) noexcept {
+            m_y = double_to_fix(lat);
+            return *this;
+        }
+
+        template <typename T>
+        T as_string(T iterator, const char separator) const {
+            iterator = osmium::util::double2string(iterator, lon(), 7);
+            *iterator++ = separator;
+            return osmium::util::double2string(iterator, lat(), 7);
+        }
+
+    }; // class Location
+
+    /**
+     * Locations are equal if both coordinates are equal.
+     */
+    inline OSMIUM_CONSTEXPR bool operator==(const Location& lhs, const Location& rhs) noexcept {
+        return lhs.x() == rhs.x() && lhs.y() == rhs.y();
+    }
+
+    inline OSMIUM_CONSTEXPR bool operator!=(const Location& lhs, const Location& rhs) noexcept {
+        return ! (lhs == rhs);
+    }
+
+    /**
+     * Compare two locations by comparing first the x and then
+     * the y coordinate. If either of the locations is
+     * undefined the result is undefined.
+     */
+    inline OSMIUM_CONSTEXPR bool operator<(const Location& lhs, const Location& rhs) noexcept {
+        return (lhs.x() == rhs.x() && lhs.y() < rhs.y()) || lhs.x() < rhs.x();
+    }
+
+    inline OSMIUM_CONSTEXPR bool operator>(const Location& lhs, const Location& rhs) noexcept {
+        return rhs < lhs;
+    }
+
+    inline OSMIUM_CONSTEXPR bool operator<=(const Location& lhs, const Location& rhs) noexcept {
+        return ! (rhs < lhs);
+    }
+
+    inline OSMIUM_CONSTEXPR bool operator>=(const Location& lhs, const Location& rhs) noexcept {
+        return ! (lhs < rhs);
+    }
+
+    /**
+     * Output a location to a stream.
+     */
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Location& location) {
+        if (location) {
+            out << '(' << location.lon() << ',' << location.lat() << ')';
+        } else {
+            out << "(undefined,undefined)";
+        }
+        return out;
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_LOCATION_HPP
diff --git a/contrib/libosmium/osmium/osm/node.hpp b/contrib/libosmium/osmium/osm/node.hpp
new file mode 100644
index 0000000..e9facef
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/node.hpp
@@ -0,0 +1,76 @@
+#ifndef OSMIUM_OSM_NODE_HPP
+#define OSMIUM_OSM_NODE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/object.hpp>
+
+namespace osmium {
+
+    namespace builder {
+        template <typename T> class ObjectBuilder;
+    }
+
+    class Node : public OSMObject {
+
+        friend class osmium::builder::ObjectBuilder<osmium::Node>;
+
+        osmium::Location m_location;
+
+        Node() :
+            OSMObject(sizeof(Node), osmium::item_type::node) {
+        }
+
+    public:
+
+        static constexpr osmium::item_type itemtype = osmium::item_type::node;
+
+        osmium::Location location() const noexcept {
+            return m_location;
+        }
+
+        Node& set_location(const osmium::Location& location) {
+            m_location = location;
+            return *this;
+        }
+
+    }; // class Node
+
+    static_assert(sizeof(Node) % osmium::memory::align_bytes == 0, "Class osmium::Node has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_NODE_HPP
diff --git a/contrib/libosmium/osmium/osm/node_ref.hpp b/contrib/libosmium/osmium/osm/node_ref.hpp
new file mode 100644
index 0000000..72359cd
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/node_ref.hpp
@@ -0,0 +1,173 @@
+#ifndef OSMIUM_OSM_NODE_REF_HPP
+#define OSMIUM_OSM_NODE_REF_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdint>
+#include <cstdlib>
+#include <iosfwd>
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    /**
+     * This reference to a node contains a node ID and a (possibly empty)
+     * location.
+     */
+    class NodeRef : public osmium::memory::detail::ItemHelper {
+
+        osmium::object_id_type m_ref;
+        osmium::Location m_location;
+
+    public:
+
+        NodeRef(const osmium::object_id_type ref = 0, const osmium::Location& location = Location()) noexcept :
+            m_ref(ref),
+            m_location(location) {
+        }
+
+        osmium::object_id_type ref() const noexcept {
+            return m_ref;
+        }
+
+        osmium::unsigned_object_id_type positive_ref() const noexcept {
+            return static_cast<osmium::unsigned_object_id_type>(std::abs(m_ref));
+        }
+
+        /**
+         * Get reference to location in this NodeRef. Can be used to update it.
+         */
+        osmium::Location& location() noexcept {
+            return m_location;
+        }
+
+        osmium::Location location() const noexcept {
+            return m_location;
+        }
+
+        double lon() const {
+            return m_location.lon();
+        }
+
+        double lat() const {
+            return m_location.lat();
+        }
+
+        int32_t x() const noexcept {
+            return m_location.x();
+        }
+
+        int32_t y() const noexcept {
+            return m_location.y();
+        }
+
+        NodeRef& set_ref(const osmium::object_id_type ref) noexcept {
+            m_ref = ref;
+            return *this;
+        }
+
+        NodeRef& set_location(const osmium::Location& location) noexcept {
+            m_location = location;
+            return *this;
+        }
+
+    }; // class NodeRef
+
+    inline bool operator==(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+        return lhs.ref() == rhs.ref();
+    }
+
+    inline bool operator!=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+        return ! (lhs == rhs);
+    }
+
+    inline bool operator<(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+        return lhs.ref() < rhs.ref();
+    }
+
+    inline bool operator>(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+        return rhs < lhs;
+    }
+
+    inline bool operator<=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+        return ! (rhs < lhs);
+    }
+
+    inline bool operator>=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+        return ! (lhs < rhs);
+    }
+
+    /**
+     * Output a NodeRef to a stream.
+     */
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::NodeRef& nr) {
+        return out << "<" << nr.ref() << " " << nr.location() << ">";
+    }
+
+    /**
+     * Functor to compare NodeRefs by Location instead of id.
+     */
+    struct location_equal {
+
+        bool operator()(const NodeRef& lhs, const NodeRef& rhs) const noexcept {
+            return lhs.location() == rhs.location();
+        }
+
+        typedef NodeRef first_argument_type;
+        typedef NodeRef second_argument_type;
+        typedef bool result_type;
+
+    }; // struct location_equal
+
+    /**
+     * Functor to compare NodeRefs by Location instead of id.
+     */
+    struct location_less {
+
+        bool operator()(const NodeRef& lhs, const NodeRef& rhs) const noexcept {
+            return lhs.location() < rhs.location();
+        }
+
+        typedef NodeRef first_argument_type;
+        typedef NodeRef second_argument_type;
+        typedef bool result_type;
+
+    }; // struct location_less
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_NODE_REF_HPP
diff --git a/contrib/libosmium/osmium/osm/node_ref_list.hpp b/contrib/libosmium/osmium/osm/node_ref_list.hpp
new file mode 100644
index 0000000..c6c4213
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/node_ref_list.hpp
@@ -0,0 +1,184 @@
+#ifndef OSMIUM_OSM_NODE_REF_LIST_HPP
+#define OSMIUM_OSM_NODE_REF_LIST_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/node_ref.hpp>
+
+namespace osmium {
+
+    /**
+     * A vector of NodeRef objects. Usually this is not instantiated directly,
+     * but one of its subclasses are used.
+     */
+    class NodeRefList : public osmium::memory::Item {
+
+    public:
+
+        NodeRefList(osmium::item_type itemtype) noexcept :
+            osmium::memory::Item(sizeof(NodeRefList), itemtype) {
+        }
+
+        /**
+         * Checks whether the node list is empty.
+         */
+        bool empty() const noexcept {
+            return sizeof(NodeRefList) == byte_size();
+        }
+
+        /**
+         * Returns the number of nodes in the list.
+         */
+        size_t size() const noexcept {
+            auto size_node_refs = byte_size() - sizeof(NodeRefList);
+            assert(size_node_refs % sizeof(NodeRef) == 0);
+            return size_node_refs / sizeof(NodeRef);
+        }
+
+        /**
+         * Access specified element.
+         *
+         * @param n Get this element of the list.
+         * @pre @code n < size() @endcode
+         */
+        const NodeRef& operator[](size_t n) const noexcept {
+            assert(n < size());
+            const NodeRef* node_ref = &*(cbegin());
+            return node_ref[n];
+        }
+
+        /**
+         * Access the first element.
+         *
+         * @pre @code !empty() @endcode
+         */
+        const NodeRef& front() const noexcept {
+            assert(!empty());
+            return operator[](0);
+        }
+
+        /**
+         * Access the last element.
+         *
+         * @pre @code !empty() @endcode
+         */
+        const NodeRef& back() const noexcept {
+            assert(!empty());
+            return operator[](size()-1);
+        }
+
+        /**
+         * Checks whether the first and last node in the list have the same ID.
+         *
+         * @pre @code !empty() @endcode
+         */
+        bool is_closed() const noexcept {
+            return front().ref() == back().ref();
+        }
+
+        /**
+         * Checks whether the first and last node in the list have the same ID.
+         *
+         * @pre @code !empty() @endcode
+         */
+        bool ends_have_same_id() const noexcept {
+            return front().ref() == back().ref();
+        }
+
+        /**
+         * Checks whether the first and last node in the list have the same
+         * location. The ID is not checked.
+         *
+         * @pre @code !empty() @endcode
+         * @pre @code front().location() && back().location() @endcode
+         */
+        bool ends_have_same_location() const {
+            assert(front().location() && back().location());
+            return front().location() == back().location();
+        }
+
+        typedef NodeRef* iterator;
+        typedef const NodeRef* const_iterator;
+        typedef std::reverse_iterator<const NodeRef*> const_reverse_iterator;
+
+        /// Returns an iterator to the beginning.
+        iterator begin() noexcept {
+            return iterator(data() + sizeof(NodeRefList));
+        }
+
+        /// Returns an iterator to the end.
+        iterator end() noexcept {
+            return iterator(data() + byte_size());
+        }
+
+        /// Returns an iterator to the beginning.
+        const_iterator cbegin() const noexcept {
+            return const_iterator(data() + sizeof(NodeRefList));
+        }
+
+        /// Returns an iterator to the end.
+        const_iterator cend() const noexcept {
+            return const_iterator(data() + byte_size());
+        }
+
+        /// Returns an iterator to the beginning.
+        const_iterator begin() const noexcept {
+            return cbegin();
+        }
+
+        /// Returns an iterator to the end.
+        const_iterator end() const noexcept {
+            return cend();
+        }
+
+        /// Returns a reverse_iterator to the beginning.
+        const_reverse_iterator crbegin() const noexcept {
+            return const_reverse_iterator(cend());
+        }
+
+        /// Returns a reverse_iterator to the end.
+        const_reverse_iterator crend() const noexcept {
+            return const_reverse_iterator(cbegin());
+        }
+
+    }; // class NodeRefList
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_NODE_REF_LIST_HPP
diff --git a/contrib/libosmium/osmium/osm/object.hpp b/contrib/libosmium/osmium/osm/object.hpp
new file mode 100644
index 0000000..c0f46ad
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/object.hpp
@@ -0,0 +1,438 @@
+#ifndef OSMIUM_OSM_OBJECT_HPP
+#define OSMIUM_OSM_OBJECT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <stdexcept>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/memory/item_iterator.hpp>
+#include <osmium/osm/entity.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/types_from_string.hpp>
+
+namespace osmium {
+
+    /**
+     * OSMObject (Node, Way, Relation, or Area).
+     */
+    class OSMObject : public osmium::OSMEntity {
+
+        object_id_type      m_id;
+        bool                m_deleted : 1;
+        object_version_type m_version : 31;
+        osmium::Timestamp   m_timestamp;
+        user_id_type        m_uid;
+        changeset_id_type   m_changeset;
+
+        size_t sizeof_object() const noexcept {
+            return sizeof(OSMObject) + (type() == item_type::node ? sizeof(osmium::Location) : 0) + sizeof(string_size_type);
+        }
+
+        unsigned char* user_position() noexcept {
+            return data() + sizeof_object() - sizeof(string_size_type);
+        }
+
+        const unsigned char* user_position() const noexcept {
+            return data() + sizeof_object() - sizeof(string_size_type);
+        }
+
+        string_size_type user_size() const noexcept {
+            return *reinterpret_cast<const string_size_type*>(user_position());
+        }
+
+        unsigned char* subitems_position() {
+            return data() + osmium::memory::padded_length(sizeof_object() + user_size());
+        }
+
+        const unsigned char* subitems_position() const {
+            return data() + osmium::memory::padded_length(sizeof_object() + user_size());
+        }
+
+    protected:
+
+        OSMObject(osmium::memory::item_size_type size, osmium::item_type type) :
+            OSMEntity(size, type),
+            m_id(0),
+            m_deleted(false),
+            m_version(0),
+            m_timestamp(),
+            m_uid(0),
+            m_changeset(0) {
+        }
+
+        void set_user_size(string_size_type size) {
+            *reinterpret_cast<string_size_type*>(user_position()) = size;
+        }
+
+    public:
+
+        /// Get ID of this object.
+        object_id_type id() const noexcept {
+            return m_id;
+        }
+
+        /// Get absolute value of the ID of this object.
+        unsigned_object_id_type positive_id() const noexcept {
+            return static_cast<unsigned_object_id_type>(std::abs(m_id));
+        }
+
+        /**
+         * Set ID of this object.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_id(object_id_type id) noexcept {
+            m_id = id;
+            return *this;
+        }
+
+        /**
+         * Set ID of this object.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_id(const char* id) {
+            return set_id(osmium::string_to_object_id(id));
+        }
+
+        /// Is this object marked as deleted?
+        bool deleted() const noexcept {
+            return m_deleted;
+        }
+
+        /// Is this object marked visible (ie not deleted)?
+        bool visible() const noexcept {
+            return !deleted();
+        }
+
+        /**
+         * Mark this object as deleted (or not).
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_deleted(bool deleted) noexcept {
+            m_deleted = deleted;
+            return *this;
+        }
+
+        /**
+         * Mark this object as visible (ie not deleted) (or not).
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_visible(bool visible) noexcept {
+            m_deleted = !visible;
+            return *this;
+        }
+
+        /**
+         * Mark this object as visible (ie not deleted) or deleted.
+         *
+         * @param visible Either "true" or "false"
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_visible(const char* visible) {
+            if (!strcmp("true", visible)) {
+                set_visible(true);
+            } else if (!strcmp("false", visible)) {
+                set_visible(false);
+            } else {
+                throw std::invalid_argument("Unknown value for visible attribute (allowed is 'true' or 'false')");
+            }
+            return *this;
+        }
+
+        /// Get version of this object.
+        object_version_type version() const noexcept {
+            return m_version;
+        }
+
+        /**
+         * Set object version.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_version(object_version_type version) noexcept {
+            m_version = version;
+            return *this;
+        }
+
+        /**
+         * Set object version.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_version(const char* version) {
+            return set_version(string_to_object_version(version));
+        }
+
+        /// Get changeset id of this object.
+        changeset_id_type changeset() const noexcept {
+            return m_changeset;
+        }
+
+        /**
+         * Set changeset id of this object.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_changeset(changeset_id_type changeset) noexcept {
+            m_changeset = changeset;
+            return *this;
+        }
+
+        /**
+         * Set changeset id of this object.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_changeset(const char* changeset) {
+            return set_changeset(string_to_changeset_id(changeset));
+        }
+
+        /// Get user id of this object.
+        user_id_type uid() const noexcept {
+            return m_uid;
+        }
+
+        /**
+         * Set user id of this object.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_uid(user_id_type uid) noexcept {
+            m_uid = uid;
+            return *this;
+        }
+
+        /**
+         * Set user id of this object.
+         * Sets uid to 0 (anonymous) if the given uid is smaller than 0.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_uid_from_signed(signed_user_id_type uid) noexcept {
+            m_uid = uid < 0 ? 0 : static_cast<user_id_type>(uid);
+            return *this;
+        }
+
+        /**
+         * Set user id of this object.
+         *
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_uid(const char* uid) {
+            return set_uid_from_signed(string_to_user_id(uid));
+        }
+
+        /// Is this user anonymous?
+        bool user_is_anonymous() const noexcept {
+            return m_uid == 0;
+        }
+
+        /// Get timestamp when this object last changed.
+        osmium::Timestamp timestamp() const noexcept {
+            return m_timestamp;
+        }
+
+        /**
+         * Set the timestamp when this object last changed.
+         *
+         * @param timestamp Timestamp
+         * @returns Reference to object to make calls chainable.
+         */
+        OSMObject& set_timestamp(const osmium::Timestamp& timestamp) noexcept {
+            m_timestamp = timestamp;
+            return *this;
+        }
+
+        /// Get user name for this object.
+        const char* user() const noexcept {
+            return reinterpret_cast<const char*>(data() + sizeof_object());
+        }
+
+        /// Get the list of tags for this object.
+        const TagList& tags() const {
+            return osmium::detail::subitem_of_type<const TagList>(cbegin(), cend());
+        }
+
+        /**
+         * Get tag value by key.
+         *
+         * Convenience function that will forward to same function on TagList
+         * object.
+         */
+        const char* get_value_by_key(const char* key, const char* default_value = nullptr) const noexcept {
+            return tags().get_value_by_key(key, default_value);
+        }
+
+        /**
+         * Set named attribute.
+         *
+         * @param attr Name of the attribute (must be one of "id", "version", "changeset", "timestamp", "uid", "visible")
+         * @param value Value of the attribute
+         */
+        void set_attribute(const char* attr, const char* value) {
+            if (!strcmp(attr, "id")) {
+                set_id(value);
+            } else if (!strcmp(attr, "version")) {
+                set_version(value);
+            } else if (!strcmp(attr, "changeset")) {
+                set_changeset(value);
+            } else if (!strcmp(attr, "timestamp")) {
+                set_timestamp(osmium::Timestamp(value));
+            } else if (!strcmp(attr, "uid")) {
+                set_uid(value);
+            } else if (!strcmp(attr, "visible")) {
+                set_visible(value);
+            }
+        }
+
+        typedef osmium::memory::CollectionIterator<Item> iterator;
+        typedef osmium::memory::CollectionIterator<const Item> const_iterator;
+
+        iterator begin() {
+            return iterator(subitems_position());
+        }
+
+        iterator end() {
+            return iterator(next());
+        }
+
+        const_iterator cbegin() const {
+            return const_iterator(subitems_position());
+        }
+
+        const_iterator cend() const {
+            return const_iterator(next());
+        }
+
+        const_iterator begin() const {
+            return cbegin();
+        }
+
+        const_iterator end() const {
+            return cend();
+        }
+
+        template <typename T>
+        using t_iterator = osmium::memory::ItemIterator<T>;
+
+        template <typename T>
+        using t_const_iterator = osmium::memory::ItemIterator<const T>;
+
+        template <typename T>
+        t_iterator<T> begin() {
+            return t_iterator<T>(subitems_position(), next());
+        }
+
+        template <typename T>
+        t_iterator<T> end() {
+            return t_iterator<T>(next(), next());
+        }
+
+        template <typename T>
+        t_const_iterator<T> cbegin() const {
+            return t_const_iterator<T>(subitems_position(), next());
+        }
+
+        template <typename T>
+        t_const_iterator<T> cend() const {
+            return t_const_iterator<T>(next(), next());
+        }
+
+        template <typename T>
+        t_const_iterator<T> begin() const {
+            return cbegin<T>();
+        }
+
+        template <typename T>
+        t_const_iterator<T> end() const {
+            return cend<T>();
+        }
+
+    }; // class OSMObject
+
+    static_assert(sizeof(OSMObject) % osmium::memory::align_bytes == 0, "Class osmium::OSMObject has wrong size to be aligned properly!");
+
+    /**
+     * OSMObjects are equal if their type, id, and version are equal.
+     */
+    inline bool operator==(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+        return lhs.type() == rhs.type() &&
+               lhs.id() == rhs.id() &&
+               lhs.version() == rhs.version();
+    }
+
+    inline bool operator!=(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+        return ! (lhs == rhs);
+    }
+
+    /**
+     * OSMObjects can be ordered by type, id and version.
+     * Note that we use the absolute value of the id for a
+     * better ordering of objects with negative id.
+     */
+    inline bool operator<(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+        if (lhs.type() != rhs.type()) {
+            return lhs.type() < rhs.type();
+        }
+        return (lhs.id() == rhs.id() && lhs.version() < rhs.version()) ||
+               lhs.positive_id() < rhs.positive_id();
+    }
+
+    inline bool operator>(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+        return rhs < lhs;
+    }
+
+    inline bool operator<=(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+        return ! (rhs < lhs);
+    }
+
+    inline bool operator>=(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+        return ! (lhs < rhs);
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_OBJECT_HPP
diff --git a/contrib/libosmium/osmium/osm/object_comparisons.hpp b/contrib/libosmium/osmium/osm/object_comparisons.hpp
new file mode 100644
index 0000000..bdf99e1
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/object_comparisons.hpp
@@ -0,0 +1,110 @@
+#ifndef OSMIUM_OSM_OBJECT_COMPARISONS_HPP
+#define OSMIUM_OSM_OBJECT_COMPARISONS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/osm/object.hpp>
+
+namespace osmium {
+
+    /**
+     * Function object class for comparing OSM objects for equality by type, id, and version.
+     */
+    struct object_equal_type_id_version {
+
+        bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
+            return lhs == rhs;
+        }
+
+        bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
+            return *lhs == *rhs;
+        }
+
+    }; // struct object_equal_type_id_version
+
+    /**
+     * Function object class for comparing OSM objects for equality by type and id,
+     * ignoring the version.
+     */
+    struct object_equal_type_id {
+
+        bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
+            return lhs.type() == rhs.type() &&
+                   lhs.id() == rhs.id();
+        }
+
+        bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
+            return operator()(*lhs, *rhs);
+        }
+
+    }; // struct object_equal_type_id
+
+    /**
+     * Function object class for ordering OSM objects by type, id, and version.
+     */
+    struct object_order_type_id_version {
+
+        bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
+            return lhs < rhs;
+        }
+
+        bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
+            return *lhs < *rhs;
+        }
+
+    }; // struct object_order_type_id_version
+
+    /**
+     * Function object class for ordering OSM objects by type, id, and reverse version,
+     * ie objects are ordered by type and id, but later versions of an object are
+     * ordered before earlier versions of the same object.
+     */
+    struct object_order_type_id_reverse_version {
+
+        bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
+            if (lhs.type() != rhs.type()) {
+                return lhs.type() < rhs.type();
+            }
+            return (lhs.id() == rhs.id() && lhs.version() > rhs.version()) ||
+                   lhs.positive_id() < rhs.positive_id();
+        }
+
+        bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
+            return operator()(*lhs, *rhs);
+        }
+
+    }; // struct object_order_type_id_reverse_version
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_OBJECT_COMPARISONS_HPP
diff --git a/contrib/libosmium/osmium/osm/relation.hpp b/contrib/libosmium/osmium/osm/relation.hpp
new file mode 100644
index 0000000..1a8b686
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/relation.hpp
@@ -0,0 +1,194 @@
+#ifndef OSMIUM_OSM_RELATION_HPP
+#define OSMIUM_OSM_RELATION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <iterator>
+
+#include <osmium/memory/collection.hpp> // IWYU pragma: keep
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    namespace builder {
+        template <typename> class ObjectBuilder;
+        class RelationMemberListBuilder;
+    }
+
+    class RelationMember : public osmium::memory::detail::ItemHelper {
+
+        friend class osmium::builder::RelationMemberListBuilder;
+
+        object_id_type   m_ref;
+        item_type        m_type;
+        uint16_t         m_flags;
+        string_size_type m_role_size {0};
+
+        RelationMember(const RelationMember&) = delete;
+        RelationMember(RelationMember&&) = delete;
+
+        RelationMember& operator=(const RelationMember&) = delete;
+        RelationMember& operator=(RelationMember&&) = delete;
+
+        unsigned char* endpos() {
+            return data() + osmium::memory::padded_length(sizeof(RelationMember) + m_role_size);
+        }
+
+        const unsigned char* endpos() const {
+            return data() + osmium::memory::padded_length(sizeof(RelationMember) + m_role_size);
+        }
+
+        template <typename TMember>
+        friend class osmium::memory::CollectionIterator;
+
+        unsigned char* next() {
+            if (full_member()) {
+                return endpos() + reinterpret_cast<osmium::memory::Item*>(endpos())->byte_size();
+            } else {
+                return endpos();
+            }
+        }
+
+        unsigned const char* next() const {
+            if (full_member()) {
+                return endpos() + reinterpret_cast<const osmium::memory::Item*>(endpos())->byte_size();
+            } else {
+                return endpos();
+            }
+        }
+
+        void set_role_size(string_size_type size) noexcept {
+            m_role_size = size;
+        }
+
+    public:
+
+        static constexpr item_type collection_type = item_type::relation_member_list;
+
+        RelationMember(const object_id_type ref = 0, const item_type type = item_type(), const bool full = false) noexcept :
+            m_ref(ref),
+            m_type(type),
+            m_flags(full ? 1 : 0) {
+        }
+
+        object_id_type ref() const noexcept {
+            return m_ref;
+        }
+
+        RelationMember& ref(object_id_type ref) noexcept {
+            m_ref = ref;
+            return *this;
+        }
+
+        unsigned_object_id_type positive_ref() const noexcept {
+            return static_cast<unsigned_object_id_type>(std::abs(m_ref));
+        }
+
+        RelationMember& set_ref(const osmium::object_id_type ref) noexcept {
+            m_ref = ref;
+            return *this;
+        }
+
+        item_type type() const noexcept {
+            return m_type;
+        }
+
+        bool full_member() const noexcept {
+            return m_flags == 1;
+        }
+
+        const char* role() const noexcept {
+            return reinterpret_cast<const char*>(data() + sizeof(RelationMember));
+        }
+
+        OSMObject& get_object() {
+            return *reinterpret_cast<OSMObject*>(endpos());
+        }
+
+        const OSMObject& get_object() const {
+            return *reinterpret_cast<const OSMObject*>(endpos());
+        }
+
+    }; // class RelationMember
+
+    class RelationMemberList : public osmium::memory::Collection<RelationMember, osmium::item_type::relation_member_list> {
+
+    public:
+
+        typedef size_t size_type;
+
+        RelationMemberList() :
+            osmium::memory::Collection<RelationMember, osmium::item_type::relation_member_list>() {
+        }
+
+        size_type size() const noexcept {
+            return static_cast<size_type>(std::distance(begin(), end()));
+        }
+
+    }; // class RelationMemberList
+
+    static_assert(sizeof(RelationMemberList) % osmium::memory::align_bytes == 0, "Class osmium::RelationMemberList has wrong size to be aligned properly!");
+
+    class Relation : public OSMObject {
+
+        friend class osmium::builder::ObjectBuilder<osmium::Relation>;
+
+        Relation() noexcept :
+            OSMObject(sizeof(Relation), osmium::item_type::relation) {
+        }
+
+    public:
+
+        static constexpr osmium::item_type itemtype = osmium::item_type::relation;
+
+        RelationMemberList& members() {
+            return osmium::detail::subitem_of_type<RelationMemberList>(begin(), end());
+        }
+
+        const RelationMemberList& members() const {
+            return osmium::detail::subitem_of_type<const RelationMemberList>(cbegin(), cend());
+        }
+
+    }; // class Relation
+
+    static_assert(sizeof(Relation) % osmium::memory::align_bytes == 0, "Class osmium::Relation has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_RELATION_HPP
diff --git a/contrib/libosmium/osmium/osm/segment.hpp b/contrib/libosmium/osmium/osm/segment.hpp
new file mode 100644
index 0000000..f3a82c9
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/segment.hpp
@@ -0,0 +1,105 @@
+#ifndef OSMIUM_OSM_SEGMENT_HPP
+#define OSMIUM_OSM_SEGMENT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iosfwd>
+#include <utility>
+
+#include <osmium/osm/location.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+    /**
+     * A Segment is the directed connection between two Locations.
+     */
+    class Segment {
+
+        osmium::Location m_first;
+        osmium::Location m_second;
+
+    public:
+
+        explicit constexpr Segment(const osmium::Location& location1, const osmium::Location& location2) noexcept :
+            m_first(location1),
+            m_second(location2) {
+        }
+
+        constexpr Segment(const Segment&) = default;
+        constexpr Segment(Segment&&) = default;
+
+        Segment& operator=(const Segment&) = default;
+        Segment& operator=(Segment&&) = default;
+
+        ~Segment() = default;
+
+        /// Return first Location of Segment.
+        OSMIUM_CONSTEXPR osmium::Location first() const noexcept {
+            return m_first;
+        }
+
+        /// Return second Location of Segment.
+        OSMIUM_CONSTEXPR osmium::Location second() const noexcept {
+            return m_second;
+        }
+
+    protected:
+
+        void swap_locations() {
+            using std::swap;
+            swap(m_first, m_second);
+        }
+
+    }; // class Segment
+
+    /// Segments are equal if both their locations are equal
+    inline OSMIUM_CONSTEXPR bool operator==(const Segment& lhs, const Segment& rhs) noexcept {
+        return lhs.first() == rhs.first() && lhs.second() == rhs.second();
+    }
+
+    inline OSMIUM_CONSTEXPR bool operator!=(const Segment& lhs, const Segment& rhs) noexcept {
+        return ! (lhs == rhs);
+    }
+
+    /**
+     * Output Segment to a stream.
+     */
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Segment& segment) {
+        return out << segment.first() << "->" << segment.second();
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_SEGMENT_HPP
diff --git a/contrib/libosmium/osmium/osm/tag.hpp b/contrib/libosmium/osmium/osm/tag.hpp
new file mode 100644
index 0000000..30e670d
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/tag.hpp
@@ -0,0 +1,140 @@
+#ifndef OSMIUM_OSM_TAG_HPP
+#define OSMIUM_OSM_TAG_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+#include <iosfwd>
+#include <iterator>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+    class Tag : public osmium::memory::detail::ItemHelper {
+
+        Tag(const Tag&) = delete;
+        Tag(Tag&&) = delete;
+
+        Tag& operator=(const Tag&) = delete;
+        Tag& operator=(Tag&&) = delete;
+
+        template <typename TMember>
+        friend class osmium::memory::CollectionIterator;
+
+        static unsigned char* after_null(unsigned char* ptr) {
+            return reinterpret_cast<unsigned char*>(std::strchr(reinterpret_cast<char*>(ptr), 0) + 1);
+        }
+
+        static const unsigned char* after_null(const unsigned char* ptr) {
+            return reinterpret_cast<const unsigned char*>(std::strchr(reinterpret_cast<const char*>(ptr), 0) + 1);
+        }
+
+        unsigned char* next() {
+            return after_null(after_null(data()));
+        }
+
+        const unsigned char* next() const {
+            return after_null(after_null(data()));
+        }
+
+    public:
+
+        static constexpr item_type collection_type = item_type::tag_list;
+
+        const char* key() const noexcept {
+            return reinterpret_cast<const char*>(data());
+        }
+
+        const char* value() const {
+            return reinterpret_cast<const char*>(after_null(data()));
+        }
+
+    }; // class Tag
+
+    inline bool operator==(const Tag& a, const Tag& b) {
+        return !std::strcmp(a.key(), b.key()) && !strcmp(a.value(), b.value());
+    }
+
+    inline bool operator<(const Tag& a, const Tag& b) {
+        return (!std::strcmp(a.key(), b.key()) && (std::strcmp(a.value(), b.value()) < 0)) || (std::strcmp(a.key(), b.key()) < 0);
+    }
+
+    /**
+     * Output a Tag to a stream.
+     */
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const Tag& tag) {
+        return out << tag.key() << '=' << tag.value();
+    }
+
+    class TagList : public osmium::memory::Collection<Tag, osmium::item_type::tag_list> {
+
+    public:
+
+        typedef size_t size_type;
+
+        TagList() :
+            osmium::memory::Collection<Tag, osmium::item_type::tag_list>() {
+        }
+
+        size_type size() const noexcept {
+            return static_cast<size_type>(std::distance(begin(), end()));
+        }
+
+        const char* get_value_by_key(const char* key, const char* default_value = nullptr) const noexcept {
+            auto result = std::find_if(cbegin(), cend(), [key](const Tag& tag) {
+                return !strcmp(tag.key(), key);
+            });
+            if (result == cend()) {
+                return default_value;
+            } else {
+                return result->value();
+            }
+        }
+
+        const char* operator[](const char* key) const noexcept {
+            return get_value_by_key(key);
+        }
+
+    }; // class TagList
+
+    static_assert(sizeof(TagList) % osmium::memory::align_bytes == 0, "Class osmium::TagList has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_TAG_HPP
diff --git a/contrib/libosmium/osmium/osm/timestamp.hpp b/contrib/libosmium/osmium/osm/timestamp.hpp
new file mode 100644
index 0000000..2145fcb
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/timestamp.hpp
@@ -0,0 +1,193 @@
+#ifndef OSMIUM_OSM_TIMESTAMP_HPP
+#define OSMIUM_OSM_TIMESTAMP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdint>
+#include <ctime>
+#include <iosfwd>
+#include <limits>
+#include <stdexcept>
+#include <string>
+
+#include <osmium/util/compatibility.hpp>
+#include <osmium/util/minmax.hpp> // IWYU pragma: keep
+
+namespace osmium {
+
+    /**
+     * A timestamp. Internal representation is an unsigned 32bit integer
+     * holding seconds since epoch, so this will overflow in 2038.
+     */
+    class Timestamp {
+
+        // length of ISO timestamp string yyyy-mm-ddThh:mm:ssZ\0
+        static constexpr int timestamp_length = 20 + 1;
+
+        /**
+         * The timestamp format for OSM timestamps in strftime(3) format.
+         * This is the ISO-Format yyyy-mm-ddThh:mm:ssZ
+         */
+        static const char* timestamp_format() {
+            static const char f[timestamp_length] = "%Y-%m-%dT%H:%M:%SZ";
+            return f;
+        }
+
+        uint32_t m_timestamp;
+
+    public:
+
+        constexpr Timestamp() noexcept :
+            m_timestamp(0) {
+        }
+
+        // Not "explicit" so that conversions from time_t work
+        // like in node.timestamp(123);
+        constexpr Timestamp(time_t timestamp) noexcept :
+            m_timestamp(static_cast<uint32_t>(timestamp)) {
+        }
+
+        /**
+         * Returns true if this timestamp is valid (ie set to something other
+         * than 0).
+         */
+        bool valid() const noexcept {
+            return m_timestamp != 0;
+        }
+
+        /**
+         * Construct timestamp from ISO date/time string.
+         * Throws std::invalid_argument, if the timestamp can not be parsed.
+         */
+        explicit Timestamp(const char* timestamp) {
+#ifndef _WIN32
+            struct tm tm {
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+            };
+            if (strptime(timestamp, timestamp_format(), &tm) == nullptr) {
+                throw std::invalid_argument("can't parse timestamp");
+            }
+            m_timestamp = static_cast<uint32_t>(timegm(&tm));
+#else
+            struct tm tm;
+            int n = sscanf(timestamp, "%4d-%2d-%2dT%2d:%2d:%2dZ", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+            if (n != 6) {
+                throw std::invalid_argument("can't parse timestamp");
+            }
+            tm.tm_year -= 1900;
+            tm.tm_mon--;
+            tm.tm_wday = 0;
+            tm.tm_yday = 0;
+            tm.tm_isdst = 0;
+            m_timestamp = static_cast<uint32_t>(_mkgmtime(&tm));
+#endif
+        }
+
+        constexpr time_t seconds_since_epoch() const noexcept {
+            return static_cast<time_t>(m_timestamp);
+        }
+
+        constexpr operator time_t() const noexcept {
+            return static_cast<time_t>(m_timestamp);
+        }
+
+        explicit constexpr operator uint32_t() const noexcept {
+            return m_timestamp;
+        }
+
+        template <typename T>
+        void operator+=(T time_difference) noexcept {
+            m_timestamp += time_difference;
+        }
+
+        template <typename T>
+        void operator-=(T time_difference) noexcept {
+            m_timestamp -= time_difference;
+        }
+
+        /**
+         * Return UTC Unix time as string in ISO date/time format.
+         */
+        std::string to_iso() const {
+            std::string s;
+
+            if (m_timestamp != 0) {
+                struct tm tm;
+                time_t sse = seconds_since_epoch();
+#ifndef _MSC_VER
+                gmtime_r(&sse, &tm);
+#else
+                gmtime_s(&tm, &sse);
+#endif
+
+                s.resize(timestamp_length);
+                /* This const_cast is ok, because we know we have enough space
+                in the string for the format we are using (well at least until
+                the year will have 5 digits). And by setting the size
+                afterwards from the result of strftime we make sure thats set
+                right, too. */
+                s.resize(strftime(const_cast<char*>(s.c_str()), timestamp_length, timestamp_format(), &tm));
+            }
+
+            return s;
+        }
+
+    }; // class Timestamp
+
+    inline OSMIUM_CONSTEXPR Timestamp start_of_time() noexcept {
+        return Timestamp(1);
+    }
+
+    inline OSMIUM_CONSTEXPR Timestamp end_of_time() noexcept {
+        return Timestamp(std::numeric_limits<time_t>::max());
+    }
+
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, Timestamp timestamp) {
+        out << timestamp.to_iso();
+        return out;
+    }
+
+    template <>
+    inline osmium::Timestamp min_op_start_value<osmium::Timestamp>() {
+        return end_of_time();
+    }
+
+    template <>
+    inline osmium::Timestamp max_op_start_value<osmium::Timestamp>() {
+        return start_of_time();
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_TIMESTAMP_HPP
diff --git a/contrib/libosmium/osmium/osm/types.hpp b/contrib/libosmium/osmium/osm/types.hpp
new file mode 100644
index 0000000..e4250d9
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/types.hpp
@@ -0,0 +1,66 @@
+#ifndef OSMIUM_OSM_TYPES_HPP
+#define OSMIUM_OSM_TYPES_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdint>
+
+namespace osmium {
+
+    /*
+     * The following typedefs are chosen so that they can represent all needed
+     * numbers and still be reasonably space efficient. As the OSM database
+     * needs 64 bit IDs for nodes, this size is used for all object IDs.
+     */
+    typedef int64_t  object_id_type;          ///< Type for OSM object (node, way, or relation) IDs.
+    typedef uint64_t unsigned_object_id_type; ///< Type for OSM object (node, way, or relation) IDs where we only allow positive IDs.
+    typedef uint32_t object_version_type;     ///< Type for OSM object version number.
+    typedef uint32_t changeset_id_type;       ///< Type for OSM changeset IDs.
+    typedef uint32_t user_id_type;            ///< Type for OSM user IDs.
+    typedef int32_t  signed_user_id_type;     ///< Type for signed OSM user IDs.
+    typedef uint32_t num_changes_type;        ///< Type for changeset num_changes.
+    typedef uint32_t num_comments_type;       ///< Type for changeset num_comments.
+
+    /**
+     * Size for strings in OSM data such as user names, tag keys, roles, etc.
+     * In Osmium they can be up to 2^16 bytes long, but OSM usually has lower
+     * defined limits.
+     */
+    typedef uint16_t string_size_type;
+
+    // maximum of 256 characters of max 4 bytes each (in UTF-8 encoding)
+    constexpr const int max_osm_string_length = 256 * 4;
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_TYPES_HPP
diff --git a/contrib/libosmium/osmium/osm/types_from_string.hpp b/contrib/libosmium/osmium/osm/types_from_string.hpp
new file mode 100644
index 0000000..b0e22a7
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/types_from_string.hpp
@@ -0,0 +1,122 @@
+#ifndef OSMIUM_OSM_TYPES_FROM_STRING_HPP
+#define OSMIUM_OSM_TYPES_FROM_STRING_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cctype>
+#include <cstdint>
+#include <cstdlib>
+#include <limits>
+#include <string>
+#include <utility>
+
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    inline object_id_type string_to_object_id(const char* input) {
+        assert(input);
+        if (*input != '\0' && !std::isspace(*input)) {
+            char* end;
+            auto id = std::strtoll(input, &end, 10);
+            if (id != std::numeric_limits<long long>::min() && id != std::numeric_limits<long long>::max() && *end == '\0') {
+                return id;
+            }
+        }
+        throw std::range_error(std::string("illegal id: '") + input + "'");
+    }
+
+    inline std::pair<osmium::item_type, osmium::object_id_type> string_to_object_id(const char* input, osmium::osm_entity_bits::type types) {
+        assert(input);
+        assert(types != osmium::osm_entity_bits::nothing);
+        if (*input != '\0') {
+            if (std::isdigit(*input)) {
+                return std::make_pair(osmium::item_type::undefined, string_to_object_id(input));
+            }
+            osmium::item_type t = osmium::char_to_item_type(*input);
+            if (osmium::osm_entity_bits::from_item_type(t) & types) {
+                return std::make_pair(t, string_to_object_id(input+1));
+            }
+        }
+        throw std::range_error(std::string("not a valid id: '") + input + "'");
+    }
+
+    namespace detail {
+
+        inline unsigned long string_to_ulong(const char* input, const char *name) {
+            if (*input != '\0' && *input != '-' && !std::isspace(*input)) {
+                char* end;
+                auto value = std::strtoul(input, &end, 10);
+                if (value != std::numeric_limits<unsigned long>::max() && *end == '\0') {
+                    return value;
+                }
+            }
+            throw std::range_error(std::string("illegal ") + name + ": '" + input + "'");
+        }
+
+    } // namespace detail
+
+    inline object_version_type string_to_object_version(const char* input) {
+        assert(input);
+        return static_cast_with_assert<object_version_type>(detail::string_to_ulong(input, "version"));
+    }
+
+    inline changeset_id_type string_to_changeset_id(const char* input) {
+        assert(input);
+        return static_cast_with_assert<changeset_id_type>(detail::string_to_ulong(input, "changeset"));
+    }
+
+    inline signed_user_id_type string_to_user_id(const char* input) {
+        assert(input);
+        if (input[0] == '-' && input[1] == '1' && input[2] == '\0') {
+            return -1;
+        }
+        return static_cast_with_assert<signed_user_id_type>(detail::string_to_ulong(input, "user id"));
+    }
+
+    inline num_changes_type string_to_num_changes(const char* input) {
+        assert(input);
+        return static_cast_with_assert<num_changes_type>(detail::string_to_ulong(input, "value for num changes"));
+    }
+
+    inline num_comments_type string_to_num_comments(const char* input) {
+        assert(input);
+        return static_cast_with_assert<num_comments_type>(detail::string_to_ulong(input, "value for num comments"));
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_TYPES_FROM_STRING_HPP
diff --git a/contrib/libosmium/osmium/osm/undirected_segment.hpp b/contrib/libosmium/osmium/osm/undirected_segment.hpp
new file mode 100644
index 0000000..654ef7d
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/undirected_segment.hpp
@@ -0,0 +1,100 @@
+#ifndef OSMIUM_OSM_UNDIRECTED_SEGMENT_HPP
+#define OSMIUM_OSM_UNDIRECTED_SEGMENT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iosfwd>
+
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/segment.hpp>
+
+namespace osmium {
+
+    /**
+     * Undirected connection between two Locations. The first Location is
+     * always equal or "smaller" than the second Location, ie to the left
+     * and down.
+     */
+    class UndirectedSegment : public Segment {
+
+    public:
+
+        explicit UndirectedSegment(const osmium::Location& location1, const osmium::Location& location2) :
+            Segment(location1, location2) {
+            if (location2 < location1) {
+                swap_locations();
+            }
+        }
+
+        UndirectedSegment(const UndirectedSegment&) = default;
+        UndirectedSegment(UndirectedSegment&&) = default;
+
+        UndirectedSegment& operator=(const UndirectedSegment&) = default;
+        UndirectedSegment& operator=(UndirectedSegment&&) = default;
+
+        ~UndirectedSegment() = default;
+
+    }; // class UndirectedSegment
+
+    /**
+     * UndirectedSegments are "smaller" if they are to the left and down of another
+     * segment. The first() location is checked first() and only if they have the
+     * same first() location the second() location is taken into account.
+     */
+    inline bool operator<(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
+        return (lhs.first() == rhs.first() && lhs.second() < rhs.second()) || lhs.first() < rhs.first();
+    }
+
+    inline bool operator>(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
+        return rhs < lhs;
+    }
+
+    inline bool operator<=(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
+        return ! (rhs < lhs);
+    }
+
+    inline bool operator>=(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
+        return ! (lhs < rhs);
+    }
+
+    /**
+     * Output UndirectedSegment to a stream.
+     */
+    template <typename TChar, typename TTraits>
+    inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::UndirectedSegment& segment) {
+        return out << segment.first() << "--" << segment.second();
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_UNDIRECTED_SEGMENT_HPP
diff --git a/contrib/libosmium/osmium/osm/way.hpp b/contrib/libosmium/osmium/osm/way.hpp
new file mode 100644
index 0000000..89380e4
--- /dev/null
+++ b/contrib/libosmium/osmium/osm/way.hpp
@@ -0,0 +1,117 @@
+#ifndef OSMIUM_OSM_WAY_HPP
+#define OSMIUM_OSM_WAY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/node_ref_list.hpp>
+
+namespace osmium {
+
+    namespace builder {
+        template <typename T> class ObjectBuilder;
+    }
+
+    /**
+     * List of node references (id and location) in a way.
+     */
+    class WayNodeList : public NodeRefList {
+
+    public:
+
+        static constexpr osmium::item_type itemtype = osmium::item_type::way_node_list;
+
+        WayNodeList():
+            NodeRefList(itemtype) {
+        }
+
+    }; // class WayNodeList
+
+    static_assert(sizeof(WayNodeList) % osmium::memory::align_bytes == 0, "Class osmium::WayNodeList has wrong size to be aligned properly!");
+
+    class Way : public OSMObject {
+
+        friend class osmium::builder::ObjectBuilder<osmium::Way>;
+
+        Way() noexcept :
+            OSMObject(sizeof(Way), osmium::item_type::way) {
+        }
+
+    public:
+
+        WayNodeList& nodes() {
+            return osmium::detail::subitem_of_type<WayNodeList>(begin(), end());
+        }
+
+        const WayNodeList& nodes() const {
+            return osmium::detail::subitem_of_type<const WayNodeList>(cbegin(), cend());
+        }
+
+        /**
+         * Update all nodes in a way with the ID of the given NodeRef with the
+         * location of the given NodeRef.
+         */
+        void update_node_location(const NodeRef& new_node_ref) {
+            for (auto& node_ref : nodes()) {
+                if (node_ref.ref() == new_node_ref.ref()) {
+                    node_ref.set_location(new_node_ref.location());
+                }
+            }
+        }
+
+        /**
+         * Do the nodes in this way form a closed ring?
+         */
+        bool is_closed() const {
+            return nodes().is_closed();
+        }
+
+        bool ends_have_same_id() const {
+            return nodes().ends_have_same_id();
+        }
+
+        bool ends_have_same_location() const {
+            return nodes().ends_have_same_location();
+        }
+
+    }; // class Way
+
+    static_assert(sizeof(Way) % osmium::memory::align_bytes == 0, "Class osmium::Way has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_WAY_HPP
diff --git a/contrib/libosmium/osmium/relations/collector.hpp b/contrib/libosmium/osmium/relations/collector.hpp
new file mode 100644
index 0000000..e7f76a2
--- /dev/null
+++ b/contrib/libosmium/osmium/relations/collector.hpp
@@ -0,0 +1,544 @@
+#ifndef OSMIUM_RELATIONS_COLLECTOR_HPP
+#define OSMIUM_RELATIONS_COLLECTOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <iomanip>
+//#include <iostream>
+#include <vector>
+
+#include <osmium/fwd.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp> // IWYU pragma: keep
+#include <osmium/osm/types.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/visitor.hpp>
+
+#include <osmium/relations/detail/relation_meta.hpp>
+#include <osmium/relations/detail/member_meta.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Code related to the assembly of OSM relations
+     */
+    namespace relations {
+
+        /**
+         * The Collector class collects members of a relation. This is a generic
+         * base class that can be used to assemble all kinds of relations. It has numerous
+         * hooks you can implement in derived classes to customize its behaviour.
+         *
+         * The collector provides two handlers (HandlerPass1 and HandlerPass2) for a first
+         * and second pass through an input file, respectively. In the first pass all
+         * relations we are interested in are stored in RelationMeta objects in the
+         * m_relations vector. All members we are interested in are stored in MemberMeta
+         * objects in the m_member_meta vectors.
+         * The MemberMeta objects also store the information where the relations containing
+         * those members are to be found.
+         *
+         * Later the m_member_meta vectors are sorted according to the
+         * member ids so that a binary search (with std::equal_range) can be used in the second
+         * pass to find the parent relations for each node, way, or relation coming along.
+         * The member objects are stored together with their relation and once a relation
+         * is complete the complete_relation() method is called which you must overwrite in
+         * a derived class of Collector.
+         *
+         * @tparam TCollector Derived class of this class.
+         *
+         * @tparam TNodes Are we interested in member nodes?
+         *
+         * @tparam TWays Are we interested in member ways?
+         *
+         * @tparam TRelations Are we interested in member relations?
+         */
+        template <typename TCollector, bool TNodes, bool TWays, bool TRelations>
+        class Collector {
+
+            /**
+             * This is the handler class for the first pass of the Collector.
+             */
+            class HandlerPass1 : public osmium::handler::Handler {
+
+                TCollector& m_collector;
+
+            public:
+
+                HandlerPass1(TCollector& collector) noexcept :
+                    m_collector(collector) {
+                }
+
+                void relation(const osmium::Relation& relation) {
+                    if (m_collector.keep_relation(relation)) {
+                        m_collector.add_relation(relation);
+                    }
+                }
+
+            }; // class HandlerPass1
+
+        public:
+
+            /**
+             * This is the handler class for the second pass of the Collector.
+             */
+            class HandlerPass2 : public osmium::handler::Handler {
+
+                TCollector& m_collector;
+
+                /**
+                 * This variable is initialized with the number of different
+                 * kinds of OSM objects we are interested in. If we only need
+                 * way members (for instance for the multipolygon collector)
+                 * it is intialized with 1 for instance. If node and way
+                 * members are needed, it is initialized with 2.
+                 *
+                 * In the after_* methods of this handler, it is decremented
+                 * and once it reaches 0, we know we have all members available
+                 * that we are ever going to get.
+                 */
+                int m_want_types;
+
+                /**
+                 * Find this object in the member vectors and add it to all
+                 * relations that need it.
+                 *
+                 * @returns true if the member was added to at least one
+                 *          relation and false otherwise
+                 */
+                bool find_and_add_object(const osmium::OSMObject& object) {
+                    auto& mmv = m_collector.member_meta(object.type());
+                    auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(object.id()));
+
+                    if (osmium::relations::count_not_removed(range.first, range.second) == 0) {
+                        // nothing found
+                        return false;
+                    }
+
+                    {
+                        m_collector.members_buffer().add_item(object);
+                        const size_t member_offset = m_collector.members_buffer().commit();
+
+                        for (auto it = range.first; it != range.second; ++it) {
+                            it->set_buffer_offset(member_offset);
+                        }
+                    }
+
+                    for (auto it = range.first; it != range.second; ++it) {
+                        MemberMeta& member_meta = *it;
+                        if (member_meta.removed()) {
+                            break;
+                        }
+                        assert(member_meta.member_id() == object.id());
+                        assert(member_meta.relation_pos() < m_collector.m_relations.size());
+                        RelationMeta& relation_meta = m_collector.m_relations[member_meta.relation_pos()];
+//                        std::cerr << "  => " << member_meta.member_pos() << " < " << m_collector.get_relation(relation_meta).members().size() << " (id=" << m_collector.get_relation(relation_meta).id() << ")\n";
+                        assert(member_meta.member_pos() < m_collector.get_relation(relation_meta).members().size());
+//                        std::cerr << "  add way " << member_meta.member_id() << " to rel " << m_collector.get_relation(relation_meta).id() << " at pos " << member_meta.member_pos() << "\n";
+                        relation_meta.got_one_member();
+                        if (relation_meta.has_all_members()) {
+                            const size_t relation_offset = member_meta.relation_pos();
+                            m_collector.complete_relation(relation_meta);
+                            m_collector.m_relations[relation_offset] = RelationMeta();
+                            m_collector.possibly_purge_removed_members();
+                        }
+                    }
+
+                    // Remove MemberMetas that were marked as removed.
+                    mmv.erase(std::remove_if(mmv.begin(), mmv.end(), [](MemberMeta& mm) {
+                        return mm.removed();
+                    }), mmv.end());
+
+                    return true;
+                }
+
+            public:
+
+                HandlerPass2(TCollector& collector) noexcept :
+                    m_collector(collector),
+                    m_want_types((TNodes?1:0) + (TWays?1:0) + (TRelations?1:0)) {
+                }
+
+                void node(const osmium::Node& node) {
+                    if (TNodes) {
+                        if (! find_and_add_object(node)) {
+                            m_collector.node_not_in_any_relation(node);
+                        }
+                    }
+                }
+
+                void way(const osmium::Way& way) {
+                    if (TWays) {
+                        if (! find_and_add_object(way)) {
+                            m_collector.way_not_in_any_relation(way);
+                        }
+                    }
+                }
+
+                void relation(const osmium::Relation& relation) {
+                    if (TRelations) {
+                        if (! find_and_add_object(relation)) {
+                            m_collector.relation_not_in_any_relation(relation);
+                        }
+                    }
+                }
+
+                void flush() {
+                    m_collector.flush();
+                }
+
+            }; // class HandlerPass2
+
+            HandlerPass2 m_handler_pass2;
+
+            // All relations we are interested in will be kept in this buffer
+            osmium::memory::Buffer m_relations_buffer;
+
+            // All members we are interested in will be kept in this buffer
+            osmium::memory::Buffer m_members_buffer;
+
+            /// Vector with all relations we are interested in
+            std::vector<RelationMeta> m_relations;
+
+            /**
+             * One vector each for nodes, ways, and relations containing all
+             * mappings from member ids to their relations.
+             */
+            std::vector<MemberMeta> m_member_meta[3];
+
+            int m_count_complete = 0;
+
+            typedef std::function<void(osmium::memory::Buffer&&)> callback_func_type;
+            callback_func_type m_callback;
+
+            static constexpr size_t initial_buffer_size = 1024 * 1024;
+
+        public:
+
+            /**
+             * Create an Collector.
+             */
+            Collector() :
+                m_handler_pass2(*static_cast<TCollector*>(this)),
+                m_relations_buffer(initial_buffer_size, osmium::memory::Buffer::auto_grow::yes),
+                m_members_buffer(initial_buffer_size, osmium::memory::Buffer::auto_grow::yes),
+                m_relations(),
+                m_member_meta() {
+            }
+
+        protected:
+
+            std::vector<MemberMeta>& member_meta(const item_type type) {
+                return m_member_meta[static_cast<uint16_t>(type) - 1];
+            }
+
+            callback_func_type callback() {
+                return m_callback;
+            }
+
+            const std::vector<RelationMeta>& relations() const {
+                return m_relations;
+            }
+
+            /**
+             * This method is called from the first pass handler for every
+             * relation in the input, to check whether it should be kept.
+             *
+             * Overwrite this method in a child class to only add relations
+             * you are interested in, for instance depending on the type tag.
+             * Storing relations takes a lot of memory, so it makes sense to
+             * filter this as much as possible.
+             */
+            bool keep_relation(const osmium::Relation& /*relation*/) const {
+                return true;
+            }
+
+            /**
+             * This method is called for every member of every relation that
+             * should be kept. It should decide if the member is interesting or
+             * not and return true or false to signal that. Only interesting
+             * members are later added to the relation.
+             *
+             * Overwrite this method in a child class. In the MultiPolygonCollector
+             * this is for instance used to only keep members of type way and
+             * ignore all others.
+             */
+            bool keep_member(const osmium::relations::RelationMeta& /*relation_meta*/, const osmium::RelationMember& /*member*/) const {
+                return true;
+            }
+
+            /**
+             * This method is called for all nodes that are not a member of
+             * any relation.
+             *
+             * Overwrite this method in a child class if you are interested
+             * in this.
+             */
+            void node_not_in_any_relation(const osmium::Node& /*node*/) {
+            }
+
+            /**
+             * This method is called for all ways that are not a member of
+             * any relation.
+             *
+             * Overwrite this method in a child class if you are interested
+             * in this.
+             */
+            void way_not_in_any_relation(const osmium::Way& /*way*/) {
+            }
+
+            /**
+             * This method is called for all relations that are not a member of
+             * any relation.
+             *
+             * Overwrite this method in a child class if you are interested
+             * in this.
+             */
+            void relation_not_in_any_relation(const osmium::Relation& /*relation*/) {
+            }
+
+            /**
+             * This method is called from the 2nd pass handler when all objects
+             * of types we are interested in have been seen.
+             *
+             * Overwrite this method in a child class if you are interested
+             * in this.
+             *
+             * Note that even after this call members might be missing if they
+             * were not in the input file! The derived class has to handle this
+             * case.
+             */
+            void flush() {
+            }
+
+            /**
+             * This removes all relations that have already been assembled
+             * from the m_relations vector.
+             */
+            void clean_assembled_relations() {
+                m_relations.erase(
+                    std::remove_if(m_relations.begin(), m_relations.end(), has_all_members()),
+                    m_relations.end()
+                );
+            }
+
+            const osmium::Relation& get_relation(size_t offset) const {
+                return m_relations_buffer.get<osmium::Relation>(offset);
+            }
+
+            /**
+             * Get the relation from a relation_meta.
+             */
+            const osmium::Relation& get_relation(const RelationMeta& relation_meta) const {
+                return get_relation(relation_meta.relation_offset());
+            }
+
+            osmium::OSMObject& get_member(size_t offset) const {
+                return m_members_buffer.get<osmium::OSMObject>(offset);
+            }
+
+            /**
+             * Tell the Collector that you are interested in this relation
+             * and want it kept until all members have been assembled and
+             * it is handed back to you.
+             *
+             * The relation is copied and stored in a buffer inside the
+             * collector.
+             */
+            void add_relation(const osmium::Relation& relation) {
+                const size_t offset = m_relations_buffer.committed();
+                m_relations_buffer.add_item(relation);
+
+                RelationMeta relation_meta(offset);
+
+                int n = 0;
+                for (auto& member : m_relations_buffer.get<osmium::Relation>(offset).members()) {
+                    if (static_cast<TCollector*>(this)->keep_member(relation_meta, member)) {
+                        member_meta(member.type()).emplace_back(member.ref(), m_relations.size(), n);
+                        relation_meta.increment_need_members();
+                    } else {
+                        member.ref(0); // set member id to zero to indicate we are not interested
+                    }
+                    ++n;
+                }
+
+                assert(offset == m_relations_buffer.committed());
+                if (relation_meta.has_all_members()) {
+                    m_relations_buffer.rollback();
+                } else {
+                    m_relations_buffer.commit();
+                    m_relations.push_back(std::move(relation_meta));
+//                    std::cerr << "added relation id=" << relation.id() << "\n";
+                }
+            }
+
+            /**
+             * Sort the vectors with the member infos so that we can do binary
+             * search on them.
+             */
+            void sort_member_meta() {
+/*                std::cerr << "relations:        " << m_relations.size() << "\n";
+                std::cerr << "node members:     " << m_member_meta[0].size() << "\n";
+                std::cerr << "way members:      " << m_member_meta[1].size() << "\n";
+                std::cerr << "relation members: " << m_member_meta[2].size() << "\n";*/
+                std::sort(m_member_meta[0].begin(), m_member_meta[0].end());
+                std::sort(m_member_meta[1].begin(), m_member_meta[1].end());
+                std::sort(m_member_meta[2].begin(), m_member_meta[2].end());
+            }
+
+        public:
+
+            uint64_t used_memory() const {
+                const uint64_t nmembers = m_member_meta[0].capacity() + m_member_meta[1].capacity() + m_member_meta[2].capacity();
+                const uint64_t members = nmembers * sizeof(MemberMeta);
+                const uint64_t relations = m_relations.capacity() * sizeof(RelationMeta);
+                const uint64_t relations_buffer_capacity = m_relations_buffer.capacity();
+                const uint64_t members_buffer_capacity = m_members_buffer.capacity();
+
+                std::cout << "  nR  = m_relations.capacity() ........... = " << std::setw(12) << m_relations.capacity() << "\n";
+                std::cout << "  nMN = m_member_meta[NODE].capacity() ... = " << std::setw(12) << m_member_meta[0].capacity() << "\n";
+                std::cout << "  nMW = m_member_meta[WAY].capacity() .... = " << std::setw(12) << m_member_meta[1].capacity() << "\n";
+                std::cout << "  nMR = m_member_meta[RELATION].capacity() = " << std::setw(12) << m_member_meta[2].capacity() << "\n";
+                std::cout << "  nM  = m_member_meta[*].capacity() ...... = " << std::setw(12) << nmembers << "\n";
+
+                std::cout << "  sRM = sizeof(RelationMeta) ............. = " << std::setw(12) << sizeof(RelationMeta) << "\n";
+                std::cout << "  sMM = sizeof(MemberMeta) ............... = " << std::setw(12) << sizeof(MemberMeta) << "\n\n";
+
+                std::cout << "  nR * sRM ............................... = " << std::setw(12) << relations << "\n";
+                std::cout << "  nM * sMM ............................... = " << std::setw(12) << members << "\n";
+                std::cout << "  relations_buffer_capacity .............. = " << std::setw(12) << relations_buffer_capacity << "\n";
+                std::cout << "  members_buffer_capacity ................ = " << std::setw(12) << members_buffer_capacity << "\n";
+
+                const uint64_t total = relations + members + relations_buffer_capacity + members_buffer_capacity;
+
+                std::cout << "  total .................................. = " << std::setw(12) << total << "\n";
+                std::cout << "  =======================================================\n";
+
+                return relations_buffer_capacity + members_buffer_capacity + relations + members;
+            }
+
+            /**
+             * Return reference to second pass handler.
+             */
+            HandlerPass2& handler(const callback_func_type& callback = nullptr) {
+                m_callback = callback;
+                return m_handler_pass2;
+            }
+
+            osmium::memory::Buffer& members_buffer() {
+                return m_members_buffer;
+            }
+
+            size_t get_offset(osmium::item_type type, osmium::object_id_type id) {
+                const auto& mmv = member_meta(type);
+                const auto range = std::equal_range(mmv.cbegin(), mmv.cend(), MemberMeta(id));
+                assert(range.first != range.second);
+                return range.first->buffer_offset();
+            }
+
+            template <typename TIter>
+            void read_relations(TIter begin, TIter end) {
+                HandlerPass1 handler(*static_cast<TCollector*>(this));
+                osmium::apply(begin, end, handler);
+                sort_member_meta();
+            }
+
+            template <typename TSource>
+            void read_relations(TSource& source) {
+                read_relations(std::begin(source), std::end(source));
+                source.close();
+            }
+
+            void moving_in_buffer(size_t old_offset, size_t new_offset) {
+                const osmium::OSMObject& object = m_members_buffer.get<osmium::OSMObject>(old_offset);
+                auto& mmv = member_meta(object.type());
+                auto range = std::equal_range(mmv.begin(), mmv.end(), osmium::relations::MemberMeta(object.id()));
+                for (auto it = range.first; it != range.second; ++it) {
+                    assert(it->buffer_offset() == old_offset);
+                    it->set_buffer_offset(new_offset);
+                }
+            }
+
+            /**
+             * Decide whether to purge removed members and then do it.
+             *
+             * Currently the purging is done every thousand calls.
+             * This could probably be improved upon.
+             */
+            void possibly_purge_removed_members() {
+                ++m_count_complete;
+                if (m_count_complete > 10000) { // XXX
+//                    const size_t size_before = m_members_buffer.committed();
+                    m_members_buffer.purge_removed(this);
+/*
+                    const size_t size_after = m_members_buffer.committed();
+                    double percent = static_cast<double>(size_before - size_after);
+                    percent /= size_before;
+                    percent *= 100;
+                    std::cerr << "PURGE (size before=" << size_before << " after=" << size_after << " purged=" << (size_before - size_after) << " / " << static_cast<int>(percent) << "%)\n";
+*/
+                    m_count_complete = 0;
+                }
+            }
+
+            /**
+             * Get a vector with pointers to all Relations that could not
+             * be completed, because members were missing in the input
+             * data.
+             *
+             * Note that these pointers point into memory allocated and
+             * owned by the Collector object.
+             */
+            std::vector<const osmium::Relation*> get_incomplete_relations() const {
+                std::vector<const osmium::Relation*> relations;
+                for (const auto& relation_meta : m_relations) {
+                    if (!relation_meta.has_all_members()) {
+                        relations.push_back(&get_relation(relation_meta));
+                    }
+                }
+                return relations;
+            }
+
+        }; // class Collector
+
+    } // namespace relations
+
+} // namespace osmium
+
+#endif // OSMIUM_RELATIONS_COLLECTOR_HPP
diff --git a/contrib/libosmium/osmium/relations/detail/member_meta.hpp b/contrib/libosmium/osmium/relations/detail/member_meta.hpp
new file mode 100644
index 0000000..ea86734
--- /dev/null
+++ b/contrib/libosmium/osmium/relations/detail/member_meta.hpp
@@ -0,0 +1,158 @@
+#ifndef OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP
+#define OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <iosfwd>
+#include <iterator>
+
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+    namespace relations {
+
+        /**
+         * Helper class for the Collector class.
+         *
+         * Stores an object ID and information where the object should be
+         * stored.
+         */
+        class MemberMeta {
+
+            /**
+             * Object ID of this relation member. Can be a node, way, or relation ID.
+             * It depends on the vector in which this object is stored which kind of
+             * object is referenced here.
+             */
+            osmium::object_id_type m_member_id;
+
+            /**
+             * Position of the relation this member is a part of in the
+             * m_relations vector.
+             */
+            size_t m_relation_pos;
+
+            /**
+             * Position of this member in the list of members of the
+             * relation this member is a part of.
+             */
+            size_t m_member_pos;
+
+            /**
+             * Offset in the buffer where the object is stored.
+             */
+            size_t m_buffer_offset { 0 };
+
+            bool m_removed = false;
+
+        public:
+
+            /**
+             * Create new MemberMeta. The variant with zeros for relation_pos and
+             * member_pos is used to create dummy MemberMeta that can be compared
+             * to the MemberMeta in the vectors using the equal_range algorithm.
+             */
+            explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos=0, size_t member_pos=0) noexcept :
+                m_member_id(member_id),
+                m_relation_pos(relation_pos),
+                m_member_pos(member_pos) {
+            }
+
+            osmium::object_id_type member_id() const noexcept {
+                return m_member_id;
+            }
+
+            size_t relation_pos() const noexcept {
+                return m_relation_pos;
+            }
+
+            size_t member_pos() const noexcept {
+                return m_member_pos;
+            }
+
+            size_t buffer_offset() const noexcept {
+                return m_buffer_offset;
+            }
+
+            void set_buffer_offset(size_t offset) noexcept {
+                m_buffer_offset = offset;
+            }
+
+            bool removed() const noexcept {
+                return m_removed;
+            }
+
+            void remove() noexcept {
+                m_removed = true;
+            }
+
+        }; // class MemberMeta
+
+        /**
+         * Compares two MemberMeta objects by only looking at the member id.
+         * Used to sort a vector of MemberMeta objects and to later find
+         * them using binary search.
+         */
+        inline bool operator<(const MemberMeta& a, const MemberMeta& b) noexcept {
+            return a.member_id() < b.member_id();
+        }
+
+        template <typename TChar, typename TTraits>
+        inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const MemberMeta& mm) {
+            out << "MemberMeta(member_id=" << mm.member_id() << " relation_pos=" << mm.relation_pos() << " member_pos=" << mm.member_pos() << " buffer_offset=" << mm.buffer_offset() << ")";
+            return out;
+        }
+
+        /**
+         * Count the number of MemberMeta objects in the iterator range
+         * that are not marked as removed.
+         *
+         * @tparam TIter Iterator that dereferences to a MemberMeta
+         * @param begin Begin of iterator range
+         * @param end End of iterator range
+         */
+        template <typename TIter>
+        inline typename std::iterator_traits<TIter>::difference_type count_not_removed(TIter begin, TIter end) {
+            return std::count_if(begin, end, [](MemberMeta& mm) {
+                return !mm.removed();
+            });
+        }
+
+    } // namespace relations
+
+} // namespace osmium
+
+#endif // OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP
diff --git a/contrib/libosmium/osmium/relations/detail/relation_meta.hpp b/contrib/libosmium/osmium/relations/detail/relation_meta.hpp
new file mode 100644
index 0000000..a48c50a
--- /dev/null
+++ b/contrib/libosmium/osmium/relations/detail/relation_meta.hpp
@@ -0,0 +1,136 @@
+#ifndef OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP
+#define OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstddef>
+#include <iosfwd>
+
+namespace osmium {
+
+    namespace relations {
+
+        /**
+         * Helper class for the Collector class.
+         *
+         * Stores information needed to collect all members of a relation. This
+         * includes the offset of the relation in a buffer plus the information
+         * needed to add members to this relation.
+         */
+        class RelationMeta {
+
+            /// The relation we are assembling.
+            size_t m_relation_offset;
+
+            /**
+             * The number of members still needed before the relation is
+             * complete. This will be set to the number of members we are
+             * interested in and then count down for every member we find.
+             * When it is 0, the relation is complete.
+             */
+            int m_need_members = 0;
+
+        public:
+
+            /**
+             * Initialize an empty RelationMeta. This is needed to zero out
+             * relations that have been completed.
+             */
+            RelationMeta() noexcept :
+                m_relation_offset(0) {
+            }
+
+            explicit RelationMeta(size_t relation_offset) noexcept :
+                m_relation_offset(relation_offset) {
+            }
+
+            /**
+             * Get offset of relation in buffer.
+             */
+            size_t relation_offset() const noexcept {
+                return m_relation_offset;
+            }
+
+            /**
+             * Increment the m_need_members counter.
+             */
+            void increment_need_members() noexcept {
+                ++m_need_members;
+            }
+
+            /**
+             * This decrements the "members needed" counter.
+             */
+            void got_one_member() {
+                assert(m_need_members > 0);
+                --m_need_members;
+            }
+
+            /**
+             * Returns true if all members for this relation are available.
+             */
+            bool has_all_members() const noexcept {
+                return m_need_members == 0;
+            }
+
+        }; // class RelationMeta
+
+        template <typename TChar, typename TTraits>
+        inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const RelationMeta& rm) {
+            out << "RelationMeta(relation_offset=" << rm.relation_offset() << " has_all_members=" << rm.has_all_members() << ")";
+            return out;
+        }
+
+        /**
+         * Function object to check if a relation is complete.
+         */
+        struct has_all_members {
+
+            typedef RelationMeta& argument_type;
+            typedef bool result_type;
+
+            /**
+             * @returns true if this relation is complete, false otherwise.
+             */
+            bool operator()(RelationMeta& relation_info) const {
+                return relation_info.has_all_members();
+            }
+
+        }; // struct has_all_members
+
+    } // namespace relations
+
+} // namespace osmium
+
+#endif // OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP
diff --git a/contrib/libosmium/osmium/tags/filter.hpp b/contrib/libosmium/osmium/tags/filter.hpp
new file mode 100644
index 0000000..0d3fc4e
--- /dev/null
+++ b/contrib/libosmium/osmium/tags/filter.hpp
@@ -0,0 +1,162 @@
+#ifndef OSMIUM_TAGS_FILTER_HPP
+#define OSMIUM_TAGS_FILTER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <boost/iterator/filter_iterator.hpp>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/osm/tag.hpp>
+
+namespace osmium {
+
+    namespace tags {
+
+        template <typename TKey>
+        struct match_key {
+            bool operator()(const TKey& rule_key, const char* tag_key) {
+                return rule_key == tag_key;
+            }
+        }; // struct match_key
+
+        struct match_key_prefix {
+            bool operator()(const std::string& rule_key, const char* tag_key) {
+                return rule_key.compare(0, std::string::npos, tag_key, 0, rule_key.size()) == 0;
+            }
+        }; // struct match_key_prefix
+
+        template <typename TValue>
+        struct match_value {
+            bool operator()(const TValue& rule_value, const char* tag_value) {
+                return rule_value == tag_value;
+            }
+        }; // struct match_value
+
+        template <>
+        struct match_value<void> {
+            bool operator()(const bool, const char*) {
+                return true;
+            }
+        }; // struct match_value<void>
+
+        template <typename TKey, typename TValue=void, typename TKeyComp=match_key<TKey>, typename TValueComp=match_value<TValue>>
+        class Filter {
+
+            typedef TKey key_type;
+            typedef typename std::conditional<std::is_void<TValue>::value, bool, TValue>::type value_type;
+
+            struct Rule {
+                key_type key;
+                value_type value;
+                bool ignore_value;
+                bool result;
+
+                explicit Rule(bool r, bool ignore, const key_type& k, const value_type& v) :
+                    key(k),
+                    value(v),
+                    ignore_value(ignore),
+                    result(r) {
+                }
+
+                explicit Rule(bool r, bool ignore, const key_type& k) :
+                    key(k),
+                    value(),
+                    ignore_value(ignore),
+                    result(r) {
+                }
+
+            }; // struct Rule
+
+            std::vector<Rule> m_rules;
+            bool m_default_result;
+
+        public:
+
+            typedef Filter<TKey, TValue, TKeyComp, TValueComp> filter_type;
+            typedef const osmium::Tag& argument_type;
+            typedef bool result_type;
+            typedef boost::filter_iterator<filter_type, osmium::TagList::const_iterator> iterator;
+
+            explicit Filter(bool default_result = false) :
+                m_default_result(default_result) {
+            }
+
+            template <typename V=TValue, typename std::enable_if<!std::is_void<V>::value, int>::type = 0>
+            Filter& add(bool result, const key_type& key, const value_type& value) {
+                m_rules.emplace_back(result, false, key, value);
+                return *this;
+            }
+
+            Filter& add(bool result, const key_type& key) {
+                m_rules.emplace_back(result, true, key);
+                return *this;
+            }
+
+            bool operator()(const osmium::Tag& tag) const {
+                for (const Rule& rule : m_rules) {
+                    if (TKeyComp()(rule.key, tag.key()) && (rule.ignore_value || TValueComp()(rule.value, tag.value()))) {
+                        return rule.result;
+                    }
+                }
+                return m_default_result;
+            }
+
+            /**
+             * Return the number of rules in this filter.
+             */
+            size_t count() const {
+                return m_rules.count();
+            }
+
+            /**
+             * Is this filter empty, ie are there no rules defined?
+             */
+            bool empty() const {
+                return m_rules.empty();
+            }
+
+        }; // class Filter
+
+        typedef Filter<std::string, std::string> KeyValueFilter;
+        typedef Filter<std::string> KeyFilter;
+        typedef Filter<std::string, void, match_key_prefix> KeyPrefixFilter;
+
+    } // namespace tags
+
+} // namespace osmium
+
+#endif // OSMIUM_TAGS_FILTER_HPP
diff --git a/contrib/libosmium/osmium/tags/regex_filter.hpp b/contrib/libosmium/osmium/tags/regex_filter.hpp
new file mode 100644
index 0000000..725c423
--- /dev/null
+++ b/contrib/libosmium/osmium/tags/regex_filter.hpp
@@ -0,0 +1,58 @@
+#ifndef OSMIUM_TAGS_REGEX_FILTER_HPP
+#define OSMIUM_TAGS_REGEX_FILTER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <regex>
+#include <string>
+
+#include <osmium/tags/filter.hpp>
+
+namespace osmium {
+
+    namespace tags {
+
+        template <>
+        struct match_value<std::regex> {
+            bool operator()(const std::regex& rule_value, const char* tag_value) {
+                return std::regex_match(tag_value, rule_value);
+            }
+        }; // struct match_value<std::regex>
+
+        typedef Filter<std::string, std::regex> RegexFilter;
+
+    } // namespace tags
+
+} // namespace osmium
+
+#endif // OSMIUM_TAGS_REGEX_FILTER_HPP
diff --git a/contrib/libosmium/osmium/tags/taglist.hpp b/contrib/libosmium/osmium/tags/taglist.hpp
new file mode 100644
index 0000000..8fc9c68
--- /dev/null
+++ b/contrib/libosmium/osmium/tags/taglist.hpp
@@ -0,0 +1,67 @@
+#ifndef OSMIUM_TAGS_TAGLIST_HPP
+#define OSMIUM_TAGS_TAGLIST_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <utility>
+
+#include <osmium/osm/tag.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Code related to working with OSM tags
+     */
+    namespace tags {
+
+        template <typename TFilter>
+        inline bool match_any_of(const osmium::TagList& tag_list, TFilter&& filter) {
+            return std::any_of(tag_list.cbegin(), tag_list.cend(), std::forward<TFilter>(filter));
+        }
+
+        template <typename TFilter>
+        inline bool match_all_of(const osmium::TagList& tag_list, TFilter&& filter) {
+            return std::all_of(tag_list.cbegin(), tag_list.cend(), std::forward<TFilter>(filter));
+        }
+
+        template <typename TFilter>
+        inline bool match_none_of(const osmium::TagList& tag_list, TFilter&& filter) {
+            return std::none_of(tag_list.cbegin(), tag_list.cend(), std::forward<TFilter>(filter));
+        }
+
+    } // namespace tags
+
+} // namespace osmium
+
+#endif // OSMIUM_TAGS_TAGLIST_HPP
diff --git a/contrib/libosmium/osmium/thread/function_wrapper.hpp b/contrib/libosmium/osmium/thread/function_wrapper.hpp
new file mode 100644
index 0000000..95b85d6
--- /dev/null
+++ b/contrib/libosmium/osmium/thread/function_wrapper.hpp
@@ -0,0 +1,123 @@
+#ifndef OSMIUM_THREAD_FUNCTION_WRAPPER_HPP
+#define OSMIUM_THREAD_FUNCTION_WRAPPER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <memory>
+
+namespace osmium {
+
+    namespace thread {
+
+        /**
+         * This function wrapper can collect move-only functions unlike
+         * std::function which needs copyable functions.
+         * Taken from the book "C++ Concurrency in Action".
+         */
+        class function_wrapper {
+
+            struct impl_base {
+
+                virtual ~impl_base() = default;
+                virtual bool call() {
+                    return true;
+                }
+
+            }; // struct impl_base
+
+            std::unique_ptr<impl_base> impl;
+
+            template <typename F>
+            struct impl_type : impl_base {
+
+                F m_functor;
+
+                impl_type(F&& functor) :
+                    m_functor(std::forward<F>(functor)) {
+                }
+
+                bool call() override {
+                    m_functor();
+                    return false;
+                }
+
+            }; // struct impl_type
+
+        public:
+
+            // Constructor must not be "explicit" for wrapper
+            // to work seemlessly.
+            template <typename TFunction>
+            function_wrapper(TFunction&& f) :
+                impl(new impl_type<TFunction>(std::forward<TFunction>(f))) {
+            }
+
+            // The integer parameter is only used to signal that we want
+            // the special function wrapper that makes the worker thread
+            // shut down.
+            function_wrapper(int) :
+                impl(new impl_base()) {
+            }
+
+            bool operator()() {
+                return impl->call();
+            }
+
+            function_wrapper() = default;
+
+            function_wrapper(function_wrapper&& other) :
+                impl(std::move(other.impl)) {
+            }
+
+            function_wrapper& operator=(function_wrapper&& other) {
+                impl = std::move(other.impl);
+                return *this;
+            }
+
+            function_wrapper(const function_wrapper&) = delete;
+            function_wrapper& operator=(const function_wrapper&) = delete;
+
+            ~function_wrapper() = default;
+
+            explicit operator bool() const {
+                return static_cast<bool>(impl);
+            }
+
+        }; // class function_wrapper
+
+    } // namespace thread
+
+} // namespace osmium
+
+#endif // OSMIUM_THREAD_FUNCTION_WRAPPER_HPP
diff --git a/contrib/libosmium/osmium/thread/pool.hpp b/contrib/libosmium/osmium/thread/pool.hpp
new file mode 100644
index 0000000..dd1023b
--- /dev/null
+++ b/contrib/libosmium/osmium/thread/pool.hpp
@@ -0,0 +1,190 @@
+#ifndef OSMIUM_THREAD_POOL_HPP
+#define OSMIUM_THREAD_POOL_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <atomic>
+#include <cstddef>
+#include <cstdlib>
+#include <future>
+#include <thread>
+#include <type_traits>
+#include <vector>
+
+#include <osmium/thread/function_wrapper.hpp>
+#include <osmium/thread/queue.hpp>
+#include <osmium/thread/util.hpp>
+#include <osmium/util/config.hpp>
+
+namespace osmium {
+
+    /**
+     * @brief Threading-related low-level code
+     */
+    namespace thread {
+
+        /**
+         *  Thread pool.
+         */
+        class Pool {
+
+            /**
+             * This class makes sure all pool threads will be joined when
+             * the pool is destructed.
+             */
+            class thread_joiner {
+
+                std::vector<std::thread>& m_threads;
+
+            public:
+
+                explicit thread_joiner(std::vector<std::thread>& threads) :
+                    m_threads(threads) {
+                }
+
+                ~thread_joiner() {
+                    for (auto& thread : m_threads) {
+                        if (thread.joinable()) {
+                            thread.join();
+                        }
+                    }
+                }
+
+            }; // class thread_joiner
+
+            osmium::thread::Queue<function_wrapper> m_work_queue;
+            std::vector<std::thread> m_threads;
+            thread_joiner m_joiner;
+            int m_num_threads;
+
+            void worker_thread() {
+                osmium::thread::set_thread_name("_osmium_worker");
+                while (true) {
+                    function_wrapper task;
+                    m_work_queue.wait_and_pop_with_timeout(task);
+                    if (task) {
+                        if (task()) {
+                            // The called tasks returns true only when the
+                            // worker thread should shut down.
+                            return;
+                        }
+                    }
+                }
+            }
+
+            /**
+             * Create thread pool with the given number of threads. If
+             * num_threads is 0, the number of threads is read from
+             * the environment variable OSMIUM_POOL_THREADS. The default
+             * value in that case is -2.
+             *
+             * If the number of threads is a negative number, it will be
+             * set to the actual number of cores on the system plus the
+             * given number, ie it will leave a number of cores unused.
+             *
+             * In all cases the minimum number of threads in the pool is 1.
+             */
+            explicit Pool(int num_threads, size_t max_queue_size) :
+                m_work_queue(max_queue_size, "work"),
+                m_threads(),
+                m_joiner(m_threads),
+                m_num_threads(num_threads) {
+
+                if (m_num_threads == 0) {
+                    m_num_threads = osmium::config::get_pool_threads();
+                }
+
+                if (m_num_threads <= 0) {
+                    m_num_threads = std::max(1, static_cast<int>(std::thread::hardware_concurrency()) + m_num_threads);
+                }
+
+                try {
+                    for (int i = 0; i < m_num_threads; ++i) {
+                        m_threads.push_back(std::thread(&Pool::worker_thread, this));
+                    }
+                } catch (...) {
+                    shutdown_all_workers();
+                    throw;
+                }
+            }
+
+        public:
+
+            static constexpr int default_num_threads = 0;
+            static constexpr size_t max_work_queue_size = 10;
+
+            static Pool& instance() {
+                static Pool pool(default_num_threads, max_work_queue_size);
+                return pool;
+            }
+
+            void shutdown_all_workers() {
+                for (int i = 0; i < m_num_threads; ++i) {
+                    // The special function wrapper makes a worker shut down.
+                    m_work_queue.push(function_wrapper{0});
+                }
+            }
+
+            ~Pool() {
+                shutdown_all_workers();
+                m_work_queue.shutdown();
+            }
+
+            size_t queue_size() const {
+                return m_work_queue.size();
+            }
+
+            bool queue_empty() const {
+                return m_work_queue.empty();
+            }
+
+            template <typename TFunction>
+            std::future<typename std::result_of<TFunction()>::type> submit(TFunction&& func) {
+
+                typedef typename std::result_of<TFunction()>::type result_type;
+
+                std::packaged_task<result_type()> task(std::forward<TFunction>(func));
+                std::future<result_type> future_result(task.get_future());
+                m_work_queue.push(std::move(task));
+
+                return future_result;
+            }
+
+        }; // class Pool
+
+    } // namespace thread
+
+} // namespace osmium
+
+#endif // OSMIUM_THREAD_POOL_HPP
diff --git a/contrib/libosmium/osmium/thread/queue.hpp b/contrib/libosmium/osmium/thread/queue.hpp
new file mode 100644
index 0000000..76ad9a0
--- /dev/null
+++ b/contrib/libosmium/osmium/thread/queue.hpp
@@ -0,0 +1,192 @@
+#ifndef OSMIUM_THREAD_QUEUE_HPP
+#define OSMIUM_THREAD_QUEUE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <cstddef>
+#include <mutex>
+#include <queue>
+#include <string>
+#include <thread>
+#include <utility> // IWYU pragma: keep (for std::move)
+
+namespace osmium {
+
+    namespace thread {
+
+        static const std::chrono::milliseconds full_queue_sleep_duration { 10 }; // XXX
+
+        /**
+         *  A thread-safe queue.
+         */
+        template <typename T>
+        class Queue {
+
+            /// Maximum size of this queue. If the queue is full pushing to
+            /// the queue will block.
+            const size_t m_max_size;
+
+            /// Name of this queue (for debugging only).
+            const std::string m_name;
+
+            mutable std::mutex m_mutex;
+
+            std::queue<T> m_queue;
+
+            /// Used to signal readers when data is available in the queue.
+            std::condition_variable m_data_available;
+
+            std::atomic<bool> m_done;
+
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+            /// The largest size the queue has been so far.
+            size_t m_largest_size;
+
+            /// The number of times the queue was full and a thread pushing
+            /// to the queue was blocked.
+            std::atomic<int> m_full_counter;
+#endif
+
+        public:
+
+            /**
+             * Construct a multithreaded queue.
+             *
+             * @param max_size Maximum number of elements in the queue. Set to
+             *                 0 for an unlimited size.
+             * @param name Optional name for this queue. (Used for debugging.)
+             */
+            Queue(size_t max_size = 0, const std::string& name = "") :
+                m_max_size(max_size),
+                m_name(name),
+                m_mutex(),
+                m_queue(),
+                m_data_available(),
+                m_done(false)
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+                ,
+                m_largest_size(0),
+                m_full_counter(0)
+#endif
+            {
+            }
+
+            ~Queue() {
+                shutdown();
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+                std::cerr << "queue '" << m_name << "' with max_size=" << m_max_size << " had largest size " << m_largest_size << " and was full " << m_full_counter << " times\n";
+#endif
+            }
+
+            /**
+             * Push an element onto the queue. If the queue has a max size, this
+             * call will block if the queue is full.
+             */
+            void push(T value) {
+                if (m_max_size) {
+                    while (size() >= m_max_size) {
+                        std::this_thread::sleep_for(full_queue_sleep_duration);
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+                        ++m_full_counter;
+#endif
+                    }
+                }
+                std::lock_guard<std::mutex> lock(m_mutex);
+                m_queue.push(std::move(value));
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+                if (m_largest_size < m_queue.size()) {
+                    m_largest_size = m_queue.size();
+                }
+#endif
+                m_data_available.notify_one();
+            }
+
+            void shutdown() {
+                m_done = true;
+                m_data_available.notify_all();
+            }
+
+            void wait_and_pop(T& value) {
+                std::unique_lock<std::mutex> lock(m_mutex);
+                m_data_available.wait(lock, [this] {
+                    return !m_queue.empty() || m_done;
+                });
+                if (!m_queue.empty()) {
+                    value = std::move(m_queue.front());
+                    m_queue.pop();
+                }
+            }
+
+            void wait_and_pop_with_timeout(T& value) {
+                std::unique_lock<std::mutex> lock(m_mutex);
+                if (!m_data_available.wait_for(lock, std::chrono::seconds(1), [this] {
+                    return !m_queue.empty() || m_done;
+                })) {
+                    return;
+                }
+                if (!m_queue.empty()) {
+                    value = std::move(m_queue.front());
+                    m_queue.pop();
+                }
+            }
+
+            bool try_pop(T& value) {
+                std::lock_guard<std::mutex> lock(m_mutex);
+                if (m_queue.empty()) {
+                    return false;
+                }
+                value = std::move(m_queue.front());
+                m_queue.pop();
+                return true;
+            }
+
+            bool empty() const {
+                std::lock_guard<std::mutex> lock(m_mutex);
+                return m_queue.empty();
+            }
+
+            size_t size() const {
+                std::lock_guard<std::mutex> lock(m_mutex);
+                return m_queue.size();
+            }
+
+        }; // class Queue
+
+    } // namespace thread
+
+} // namespace osmium
+
+#endif // OSMIUM_THREAD_QUEUE_HPP
diff --git a/contrib/libosmium/osmium/thread/sorted_queue.hpp b/contrib/libosmium/osmium/thread/sorted_queue.hpp
new file mode 100644
index 0000000..e76ade1
--- /dev/null
+++ b/contrib/libosmium/osmium/thread/sorted_queue.hpp
@@ -0,0 +1,159 @@
+#ifndef OSMIUM_THREAD_SORTED_QUEUE_HPP
+#define OSMIUM_THREAD_SORTED_QUEUE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <condition_variable>
+#include <cstddef>
+#include <deque>
+#include <mutex>
+
+namespace osmium {
+
+    namespace thread {
+
+        /**
+         * This implements a sorted queue. It is a bit like a priority
+         * queue. We have n worker threads pushing items into the queue
+         * and one thread pulling them out again "in order". The order
+         * is defined by the monotonically increasing "num" parameter
+         * to the push() method. The wait_and_pop() and try_pop() methods
+         * will only give out the next numbered item. This way several
+         * workers can work in their own time on different pieces of
+         * some incoming data, but it all gets serialized properly again
+         * after the workers have done their work.
+         */
+        template <typename T>
+        class SortedQueue {
+
+            typedef typename std::deque<T>::size_type size_type;
+
+            mutable std::mutex m_mutex;
+            std::deque<T> m_queue;
+            std::condition_variable m_data_available;
+
+            size_type m_offset;
+
+            // this method expects that we already have the lock
+            bool empty_intern() const {
+                return m_queue.front() == T();
+            }
+
+        public:
+
+            SortedQueue() :
+                m_mutex(),
+                m_queue(1),
+                m_data_available(),
+                m_offset(0) {
+            }
+
+            /**
+             * Push an item into the queue.
+             *
+             * @param value The item to push into the queue.
+             * @param num Number to describe ordering for the items.
+             *            It must increase monotonically.
+             */
+            void push(T value, size_type num) {
+                std::lock_guard<std::mutex> lock(m_mutex);
+
+                num -= m_offset;
+                if (m_queue.size() <= num + 1) {
+                    m_queue.resize(num + 2);
+                }
+                m_queue[num] = std::move(value);
+
+                m_data_available.notify_one();
+            }
+
+            /**
+             * Wait until the next item becomes available and make it
+             * available through value.
+             */
+            void wait_and_pop(T& value) {
+                std::unique_lock<std::mutex> lock(m_mutex);
+
+                m_data_available.wait(lock, [this] {
+                    return !empty_intern();
+                });
+                value = std::move(m_queue.front());
+                m_queue.pop_front();
+                ++m_offset;
+            }
+
+            /**
+             * Get next item if it is available and return true. Or
+             * return false otherwise.
+             */
+            bool try_pop(T& value) {
+                std::lock_guard<std::mutex> lock(m_mutex);
+
+                if (empty_intern()) {
+                    return false;
+                }
+                value = std::move(m_queue.front());
+                m_queue.pop_front();
+                ++m_offset;
+                return true;
+            }
+
+            /**
+             * The queue is empty. This means try_pop() would fail if called.
+             * It does not mean that there is nothing on the queue. Because
+             * the queue is sorted, it could mean that the next item in the
+             * queue is not available, but other items are.
+             */
+            bool empty() const {
+                std::lock_guard<std::mutex> lock(m_mutex);
+
+                return empty_intern();
+            }
+
+            /**
+             * Returns the number of items in the queue, regardless of whether
+             * they can be accessed. If this is =0 it
+             * implies empty()==true, but not the other way around.
+             */
+            size_t size() const {
+                std::lock_guard<std::mutex> lock(m_mutex);
+                return m_queue.size();
+            }
+
+        }; // class SortedQueue
+
+    } // namespace thread
+
+} // namespace osmium
+
+#endif // OSMIUM_THREAD_SORTED_QUEUE_HPP
diff --git a/contrib/libosmium/osmium/thread/util.hpp b/contrib/libosmium/osmium/thread/util.hpp
new file mode 100644
index 0000000..00de0d8
--- /dev/null
+++ b/contrib/libosmium/osmium/thread/util.hpp
@@ -0,0 +1,116 @@
+#ifndef OSMIUM_THREAD_UTIL_HPP
+#define OSMIUM_THREAD_UTIL_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <chrono>
+#include <future>
+
+#ifdef __linux__
+# include <sys/prctl.h>
+#endif
+
+namespace osmium {
+
+    namespace thread {
+
+        /**
+         * Check if the future resulted in an exception. This will re-throw
+         * the exception stored in the future if there was one. Otherwise it
+         * will just return.
+         */
+        template <typename T>
+        inline void check_for_exception(std::future<T>& future) {
+            if (future.valid() && future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+                future.get();
+            }
+        }
+
+        /**
+         * Wait until the given future becomes ready. Will block if the future
+         * is not ready. Can be called more than once unlike future.get().
+         */
+        template <typename T>
+        inline void wait_until_done(std::future<T>& future) {
+            if (future.valid()) {
+                future.get();
+            }
+        }
+
+        /**
+         * Set name of current thread for debugging. This only works on Linux.
+         */
+#ifdef __linux__
+        inline void set_thread_name(const char* name) noexcept {
+            prctl(PR_SET_NAME, name, 0, 0, 0);
+        }
+#else
+        inline void set_thread_name(const char*) noexcept {
+            // intentionally left blank
+        }
+#endif
+
+        class thread_handler {
+
+            std::thread m_thread;
+
+        public:
+
+            thread_handler() :
+                m_thread() {
+            }
+
+            template <typename TFunction, typename... TArgs>
+            thread_handler(TFunction&& f, TArgs&&... args) :
+                m_thread(std::forward<TFunction>(f), std::forward<TArgs>(args)...) {
+            }
+
+            thread_handler(const thread_handler&) = delete;
+            thread_handler& operator=(const thread_handler&) = delete;
+
+            thread_handler(thread_handler&&) = default;
+            thread_handler& operator=(thread_handler&&) = default;
+
+            ~thread_handler() {
+                if (m_thread.joinable()) {
+                    m_thread.join();
+                }
+            }
+
+        }; // class thread_handler
+
+    } // namespace thread
+
+} // namespace osmium
+
+#endif //  OSMIUM_THREAD_UTIL_HPP
diff --git a/contrib/libosmium/osmium/util/cast.hpp b/contrib/libosmium/osmium/util/cast.hpp
new file mode 100644
index 0000000..4866fde
--- /dev/null
+++ b/contrib/libosmium/osmium/util/cast.hpp
@@ -0,0 +1,103 @@
+#ifndef OSMIUM_UTIL_CAST_HPP
+#define OSMIUM_UTIL_CAST_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#ifndef assert
+# include <cassert>
+#endif
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+namespace osmium {
+
+    // These functions are wrappers around static_cast<>() that call assert()
+    // to check that there is no integer overflow happening before doing the
+    // cast. There are several versions of this templated function here
+    // depending on the types of the input and output. In any case, both input
+    // and output have to be integral types. If the cast can't overflow, no
+    // check is done.
+
+    template <typename A, typename B>
+    struct are_real_integers :
+        std::integral_constant<bool,
+            std::is_integral<A>::value &&
+            std::is_integral<B>::value &&
+            !std::is_same<A, bool>::value &&
+            !std::is_same<B, bool>::value> {
+    };
+
+    template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && std::is_same<T, F>::value, int>::type = 0>
+    inline T static_cast_with_assert(const F value) {
+        return value;
+    }
+
+    template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && (sizeof(T) > sizeof(F)), int>::type = 0>
+    inline T static_cast_with_assert(const F value) {
+        return static_cast<T>(value);
+    }
+
+    template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && std::is_signed<T>::value == std::is_signed<F>::value && (sizeof(T) == sizeof(F)), int>::type = 0>
+    inline T static_cast_with_assert(const F value) {
+        return static_cast<T>(value);
+    }
+
+    template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && (sizeof(T) < sizeof(F)) && std::is_signed<T>::value && std::is_signed<F>::value, int>::type = 0>
+    inline T static_cast_with_assert(const F value) {
+        assert(value >= std::numeric_limits<T>::min() && value <= std::numeric_limits<T>::max());
+        return static_cast<T>(value);
+    }
+
+    template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && (sizeof(T) <= sizeof(F)) && std::is_unsigned<T>::value && std::is_signed<F>::value, int>::type = 0>
+    inline T static_cast_with_assert(const F value) {
+        assert(value >= 0 && static_cast<typename std::make_unsigned<F>::type>(value) <= std::numeric_limits<T>::max());
+        return static_cast<T>(value);
+    }
+
+    template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && (sizeof(T) < sizeof(F)) && std::is_unsigned<T>::value && std::is_unsigned<F>::value, int>::type = 0>
+    inline T static_cast_with_assert(const F value) {
+        assert(value <= std::numeric_limits<T>::max());
+        return static_cast<T>(value);
+    }
+
+    template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && (sizeof(T) <= sizeof(F)) && std::is_signed<T>::value && std::is_unsigned<F>::value, int>::type = 0>
+    inline T static_cast_with_assert(const F value) {
+        assert(static_cast<int64_t>(value) <= static_cast<int64_t>(std::numeric_limits<T>::max()));
+        return static_cast<T>(value);
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_CAST_HPP
diff --git a/contrib/libosmium/osmium/util/compatibility.hpp b/contrib/libosmium/osmium/util/compatibility.hpp
new file mode 100644
index 0000000..23753ce
--- /dev/null
+++ b/contrib/libosmium/osmium/util/compatibility.hpp
@@ -0,0 +1,56 @@
+#ifndef OSMIUM_UTIL_COMPATIBILITY_HPP
+#define OSMIUM_UTIL_COMPATIBILITY_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+// Workarounds for MSVC which doesn't support
+// * constexpr in all cases yet
+// * [[noreturn]]
+#ifdef _MSC_VER
+# define OSMIUM_CONSTEXPR
+# define OSMIUM_NORETURN __declspec(noreturn)
+#else
+# define OSMIUM_CONSTEXPR constexpr
+# define OSMIUM_NORETURN [[noreturn]]
+#endif
+
+// [[deprecated]] is only available in C++14, use this for the time being
+#ifdef __GNUC__
+# define OSMIUM_DEPRECATED __attribute__((deprecated))
+#elif defined(_MSC_VER)
+# define OSMIUM_DEPRECATED __declspec(deprecated)
+#else
+# define OSMIUM_DEPRECATED
+#endif
+
+#endif // OSMIUM_UTIL_COMPATIBILITY_HPP
diff --git a/contrib/libosmium/osmium/util/config.hpp b/contrib/libosmium/osmium/util/config.hpp
new file mode 100644
index 0000000..3285eed
--- /dev/null
+++ b/contrib/libosmium/osmium/util/config.hpp
@@ -0,0 +1,72 @@
+#ifndef OSMIUM_UTIL_CONFIG_HPP
+#define OSMIUM_UTIL_CONFIG_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdlib>
+#include <cstring>
+
+#ifdef _MSC_VER
+# define strcasecmp _stricmp
+#endif
+
+namespace osmium {
+
+    namespace config {
+
+        inline int get_pool_threads() {
+            const char* env = getenv("OSMIUM_POOL_THREADS");
+            if (env) {
+                return std::atoi(env);
+            }
+            return -2;
+        }
+
+        inline bool use_pool_threads_for_pbf_parsing() {
+            const char* env = getenv("OSMIUM_USE_POOL_THREADS_FOR_PBF_PARSING");
+            if (env) {
+                if (!strcasecmp(env, "off") ||
+                    !strcasecmp(env, "false") ||
+                    !strcasecmp(env, "no") ||
+                    !strcasecmp(env, "0")) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+    } // namespace config
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_CONFIG_HPP
diff --git a/contrib/libosmium/osmium/util/data_file.hpp b/contrib/libosmium/osmium/util/data_file.hpp
new file mode 100644
index 0000000..53bb81c
--- /dev/null
+++ b/contrib/libosmium/osmium/util/data_file.hpp
@@ -0,0 +1,194 @@
+#ifndef OSMIUM_UTIL_DATA_FILE_HPP
+#define OSMIUM_UTIL_DATA_FILE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cerrno>
+#include <cstddef>
+#include <cstdio>
+#include <stdexcept>
+#include <string>
+#include <system_error>
+
+#ifdef _WIN32
+# include <io.h>
+# include <windows.h>
+#endif
+
+#include <osmium/util/file.hpp>
+
+namespace osmium {
+
+    namespace util {
+
+        /**
+         * Class wrapper for convenient access to some low-level file
+         * functions.
+         */
+        class DataFile {
+
+            FILE* m_file;
+
+        public:
+
+            /**
+             * Create and open a temporary file. It is removed after opening.
+             *
+             * @throws std::system_error if something went wrong.
+             */
+            DataFile() :
+                m_file(::tmpfile()) {
+                if (!m_file) {
+                    throw std::system_error(errno, std::system_category(), "tmpfile failed");
+                }
+            }
+
+            /**
+             * Create and open a temporary file with the specified size. It
+             * is removed after opening.
+             *
+             * @throws std::system_error if something went wrong.
+             */
+            explicit DataFile(size_t size) :
+                DataFile() {
+                grow(size);
+            }
+
+            /**
+             * Create and open a named file.
+             *
+             * @param filename the name of the file
+             * @param writable should the file be writable?
+             * @throws std::system_error if something went wrong.
+             */
+            DataFile(const char* filename, bool writable) :
+                m_file(::fopen(filename, writable ? "wb+" : "rb" )) {
+                if (!m_file) {
+                    throw std::system_error(errno, std::system_category(), "fopen failed");
+                }
+            }
+
+            /**
+             * Create and open a named file.
+             *
+             * @param filename the name of the file
+             * @param writable should the file be writable?
+             * @throws std::system_error if something went wrong.
+             */
+            DataFile(const std::string& filename, bool writable) :
+                DataFile(filename.c_str(), writable) {
+            }
+
+            /**
+             * In boolean context the DataFile class returns true if the file
+             * is open.
+             */
+            operator bool() const noexcept {
+                return m_file != nullptr;
+            }
+
+            /**
+             * Close the file.
+             *
+             * Does nothing if the file is already closed.
+             *
+             * @throws std::system_error if file could not be closed
+             */
+            void close() {
+                if (m_file) {
+                    if (::fclose(m_file) != 0) {
+                        throw std::system_error(errno, std::system_category(), "fclose failed");
+                    }
+                    m_file = nullptr;
+                }
+            }
+
+            ~DataFile() noexcept {
+                try {
+                    close();
+                } catch (std::system_error&) {
+                    // Ignore any exceptions because destructor must not throw.
+                }
+            }
+
+            /**
+             * Get file descriptor of underlying file.
+             *
+             * @throws std::runtime_errro if file is not open
+             * @throws std::system_error if fileno(3) call failed
+             */
+            int fd() const {
+                if (!m_file) {
+                    throw std::runtime_error("no open file");
+                }
+
+                int fd = ::fileno(m_file);
+
+                if (fd == -1) {
+                    throw std::system_error(errno, std::system_category(), "fileno failed");
+                }
+
+                return fd;
+            }
+
+            /**
+             * Ask the operating system for the size of this file.
+             *
+             * @throws std::system_error if fstat(2) call failed
+             */
+            size_t size() const {
+                return osmium::util::file_size(fd());
+            }
+
+            /**
+             * Grow file to given size.
+             *
+             * If the file is large enough already, nothing is done.
+             * The file is never shrunk.
+             *
+             * @throws std::system_error if ftruncate(2) call failed
+             */
+            void grow(size_t new_size) const {
+                if (size() < new_size) {
+                    osmium::util::resize_file(fd(), new_size);
+                }
+            }
+
+        }; // class DataFile
+
+    } // namespace util
+
+} // namespace osmium
+
+
+#endif // OSMIUM_UTIL_DATA_FILE_HPP
diff --git a/contrib/libosmium/osmium/util/delta.hpp b/contrib/libosmium/osmium/util/delta.hpp
new file mode 100644
index 0000000..cdf3674
--- /dev/null
+++ b/contrib/libosmium/osmium/util/delta.hpp
@@ -0,0 +1,174 @@
+#ifndef OSMIUM_UTIL_DELTA_HPP
+#define OSMIUM_UTIL_DELTA_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iterator>
+#include <type_traits>
+#include <utility>
+
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    namespace util {
+
+        /**
+         * Helper class for delta encoding.
+         */
+        template <typename TValue, typename TDelta = int64_t>
+        class DeltaEncode {
+
+            static_assert(std::is_integral<TValue>::value,
+                          "DeltaEncode value type must be some integer");
+
+            static_assert(std::is_integral<TDelta>::value && std::is_signed<TDelta>::value,
+                          "DeltaEncode delta type must be some signed integer");
+
+            TValue m_value;
+
+        public:
+
+            using value_type = TValue;
+            using delta_type = TDelta;
+
+            DeltaEncode(TValue value = 0) :
+                m_value(value) {
+            }
+
+            void clear() noexcept {
+                m_value = 0;
+            }
+
+            TValue value() const noexcept {
+                return m_value;
+            }
+
+            TDelta update(TValue new_value) noexcept {
+                using std::swap;
+                swap(m_value, new_value);
+                return static_cast_with_assert<TDelta>(m_value) -
+                       static_cast_with_assert<TDelta>(new_value);
+            }
+
+        }; // class DeltaEncode
+
+        /**
+         * Helper class for delta decoding.
+         */
+        template <typename TValue, typename TDelta = int64_t>
+        class DeltaDecode {
+
+            static_assert(std::is_integral<TValue>::value,
+                          "DeltaDecode value type must be some integer");
+
+            static_assert(std::is_integral<TDelta>::value && std::is_signed<TDelta>::value,
+                          "DeltaDecode delta type must be some signed integer");
+
+            TValue m_value;
+
+        public:
+
+            using value_type = TValue;
+            using delta_type = TDelta;
+
+            DeltaDecode() :
+                m_value(0) {
+            }
+
+            void clear() noexcept {
+                m_value = 0;
+            }
+
+            TValue update(TDelta delta) noexcept {
+                m_value = static_cast_with_assert<TValue>(
+                              static_cast_with_assert<TDelta>(m_value) + delta);
+                return m_value;
+            }
+
+        }; // class DeltaDecode
+
+        template <typename TBaseIterator, typename TTransform, typename TValue, typename TDelta = int64_t>
+        class DeltaEncodeIterator : public std::iterator<std::input_iterator_tag, TValue> {
+
+            TBaseIterator m_it;
+            TBaseIterator m_end;
+            TTransform m_trans;
+            DeltaEncode<TValue, TDelta> m_value;
+            TDelta m_delta;
+
+        public:
+
+            using value_type = TValue;
+            using delta_type = TDelta;
+
+            DeltaEncodeIterator(TBaseIterator first, TBaseIterator last, TTransform& trans) :
+                m_it(first),
+                m_end(last),
+                m_trans(trans),
+                m_value(m_it != m_end ? m_trans(m_it) : 0),
+                m_delta(static_cast_with_assert<TDelta>(m_value.value())) {
+            }
+
+            DeltaEncodeIterator& operator++() {
+                if (++m_it != m_end) {
+                    m_delta = m_value.update(m_trans(m_it));
+                }
+                return *this;
+            }
+
+            DeltaEncodeIterator operator++(int) {
+                DeltaEncodeIterator tmp(*this);
+                operator++();
+                return tmp;
+            }
+
+            TDelta operator*() {
+                return m_delta;
+            }
+
+            bool operator==(const DeltaEncodeIterator& rhs) const {
+                return m_it == rhs.m_it && m_end == rhs.m_end;
+            }
+
+            bool operator!=(const DeltaEncodeIterator& rhs) const {
+                return !(*this == rhs);
+            }
+
+        }; // class DeltaEncodeIterator
+
+    } // namespace util
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_DELTA_HPP
diff --git a/contrib/libosmium/osmium/util/double.hpp b/contrib/libosmium/osmium/util/double.hpp
new file mode 100644
index 0000000..85a2508
--- /dev/null
+++ b/contrib/libosmium/osmium/util/double.hpp
@@ -0,0 +1,93 @@
+#ifndef OSMIUM_UTIL_DOUBLE_HPP
+#define OSMIUM_UTIL_DOUBLE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstdio>
+#include <iterator>
+#include <string>
+
+namespace osmium {
+
+    namespace util {
+
+        constexpr int max_double_length = 20; // should fit any double
+
+        /**
+         * Write double to iterator, removing superfluous '0' characters at
+         * the end. The decimal dot will also be removed if necessary.
+         *
+         * @tparam T iterator type
+         * @param iterator output iterator
+         * @param value the value that should be written
+         * @param precision max number of digits after the decimal point (must be <= 17)
+         */
+        template <typename T>
+        inline T double2string(T iterator, double value, int precision) {
+            assert(precision <= 17);
+
+            char buffer[max_double_length];
+
+#ifndef _MSC_VER
+            int len = snprintf(buffer, max_double_length, "%.*f", precision, value);
+#else
+            int len = _snprintf(buffer, max_double_length, "%.*f", precision, value);
+#endif
+            assert(len > 0 && len < max_double_length);
+
+            while (buffer[len-1] == '0') --len;
+            if (buffer[len-1] == '.') --len;
+
+            return std::copy_n(buffer, len, iterator);
+        }
+
+        /**
+         * Write double to string, removing superfluous '0' characters at
+         * the end. The decimal dot will also be removed if necessary.
+         *
+         * @param out string
+         * @param value the value that should be written
+         * @param precision max number of digits after the decimal point
+         */
+        inline void double2string(std::string& out, double value, int precision) {
+            double2string(std::back_inserter(out), value, precision);
+        }
+
+    } // namespace util
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_DOUBLE_HPP
diff --git a/contrib/libosmium/osmium/util/endian.hpp b/contrib/libosmium/osmium/util/endian.hpp
new file mode 100644
index 0000000..a5d9154
--- /dev/null
+++ b/contrib/libosmium/osmium/util/endian.hpp
@@ -0,0 +1,45 @@
+#ifndef OSMIUM_UTIL_ENDIAN_HPP
+#define OSMIUM_UTIL_ENDIAN_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+// Windows is only available for little endian architectures
+// http://stackoverflow.com/questions/6449468/can-i-safely-assume-that-windows-installations-will-always-be-little-endian
+#if !defined(_WIN32) && !defined(__APPLE__)
+# include <endian.h>
+#else
+# define __LITTLE_ENDIAN 1234
+# define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+
+#endif // OSMIUM_UTIL_ENDIAN_HPP
diff --git a/contrib/libosmium/osmium/util/file.hpp b/contrib/libosmium/osmium/util/file.hpp
new file mode 100644
index 0000000..39e01af
--- /dev/null
+++ b/contrib/libosmium/osmium/util/file.hpp
@@ -0,0 +1,121 @@
+#ifndef OSMIUM_UTIL_FILE_HPP
+#define OSMIUM_UTIL_FILE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cerrno>
+#include <cstddef>
+#include <cstdio>
+#include <system_error>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifdef _WIN32
+# include <io.h>
+# include <windows.h>
+#endif
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#else
+// https://msdn.microsoft.com/en-us/library/whx354w1.aspx
+# define ftruncate _chsize_s
+#endif
+
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+    namespace util {
+
+        /**
+         * Get file size.
+         * This is a small wrapper around a system call.
+         *
+         * @param fd File descriptor
+         * @returns file size
+         * @throws std::system_error If system call failed
+         */
+        inline size_t file_size(int fd) {
+#ifdef _MSC_VER
+            // Windows implementation
+            // https://msdn.microsoft.com/en-us/library/dfbc2kec.aspx
+            auto size = ::_filelengthi64(fd);
+            if (size == -1L) {
+                throw std::system_error(errno, std::system_category(), "_filelengthi64 failed");
+            }
+            return size_t(size);
+#else
+            // Unix implementation
+            struct stat s;
+            if (::fstat(fd, &s) != 0) {
+                throw std::system_error(errno, std::system_category(), "fstat failed");
+            }
+            return size_t(s.st_size);
+#endif
+        }
+
+        /**
+         * Resize file.
+         * Small wrapper around ftruncate(2) system call.
+         *
+         * @param fd File descriptor
+         * @param new_size New size
+         * @throws std::system_error If ftruncate(2) call failed
+         */
+        inline void resize_file(int fd, size_t new_size) {
+            if (::ftruncate(fd, static_cast_with_assert<off_t>(new_size)) != 0) {
+                throw std::system_error(errno, std::system_category(), "ftruncate failed");
+            }
+        }
+
+        /**
+         * Get the page size for this system.
+         */
+        inline size_t get_pagesize() {
+#ifdef _WIN32
+            // Windows implementation
+            SYSTEM_INFO si;
+            GetSystemInfo(&si);
+            return si.dwPageSize;
+#else
+            // Unix implementation
+            return size_t(::sysconf(_SC_PAGESIZE));
+#endif
+        }
+
+    } // namespace util
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_FILE_HPP
diff --git a/contrib/libosmium/osmium/util/memory_mapping.hpp b/contrib/libosmium/osmium/util/memory_mapping.hpp
new file mode 100644
index 0000000..d5a057d
--- /dev/null
+++ b/contrib/libosmium/osmium/util/memory_mapping.hpp
@@ -0,0 +1,757 @@
+#ifndef OSMIUM_UTIL_MEMORY_MAPPING_HPP
+#define OSMIUM_UTIL_MEMORY_MAPPING_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cerrno>
+#include <stdexcept>
+#include <system_error>
+
+#include <osmium/util/file.hpp>
+
+#ifndef _WIN32
+# include <sys/mman.h>
+#else
+# include <fcntl.h>
+# include <io.h>
+# include <windows.h>
+# include <sys/types.h>
+#endif
+
+namespace osmium {
+
+    namespace util {
+
+        /**
+         * Class for wrapping memory mapping system calls.
+         *
+         * Usage for anonymous mapping:
+         * @code
+         * MemoryMapping mapping(1024);          // create anonymous mapping with size
+         * auto ptr = mapping.get_addr<char*>(); // get pointer to memory
+         * mapping.unmap();                      // release mapping by calling unmap() (or at end of scope)
+         * @endcode
+         *
+         * Or for file-backed mapping:
+         * @code
+         * int fd = ::open(...);
+         * {
+         *     MemoryMapping mapping(1024, MemoryMapping::mapping_mode::write_shared, fd, offset);
+         *     // use mapping
+         * }
+         * ::close(fd);
+         * @endcode
+         *
+         * If the file backing a file-backed mapping is not large enough, it
+         * will be resized. This works, of course, only for writable files,
+         * so for read-only files you have to make sure they are large enough
+         * for any mapping you want.
+         *
+         * If you ask for a zero-sized mapping, a mapping of the systems page
+         * size will be created instead. For file-backed mapping this will only
+         * work if the file is writable.
+         *
+         * There are different implementations for Unix and Windows systems.
+         * On Unix systems this wraps the mmap(), munmap(), and the mremap()
+         * system calls. On Windows it wraps the CreateFileMapping(),
+         * CloseHandle(), MapViewOfFile(), and UnmapViewOfFile() functions.
+         *
+         * On Windows the file will be set to binary mode before the memory
+         * mapping.
+         */
+        class MemoryMapping {
+
+public:
+            enum class mapping_mode {
+                readonly      = 0,
+                write_private = 1,
+                write_shared  = 2
+            };
+
+private:
+
+            /// The size of the mapping
+            size_t m_size;
+
+            /// Offset into the file
+            off_t m_offset;
+
+            /// File handle we got the mapping from
+            int m_fd;
+
+            /// Mapping mode
+            mapping_mode m_mapping_mode;
+
+#ifdef _WIN32
+            HANDLE m_handle;
+#endif
+
+            /// The address where the memory is mapped
+            void* m_addr;
+
+            bool is_valid() const noexcept;
+
+            void make_invalid() noexcept;
+
+#ifdef _WIN32
+            typedef DWORD flag_type;
+#else
+            typedef int flag_type;
+#endif
+
+            flag_type get_protection() const noexcept;
+
+            flag_type get_flags() const noexcept;
+
+            // A zero-sized mapping is not allowed by the operating system.
+            // So if the user asks for a mapping of size 0, we map a full
+            // page instead. This way we don't have a special case in the rest
+            // of the code.
+            static size_t initial_size(size_t size) {
+                if (size == 0) {
+                    return osmium::util::get_pagesize();
+                }
+                return size;
+            }
+
+#ifdef _WIN32
+            HANDLE get_handle() const noexcept;
+            HANDLE osmium::util::MemoryMapping::create_file_mapping() const noexcept;
+            void* osmium::util::MemoryMapping::map_view_of_file() const noexcept;
+#endif
+
+            int resize_fd(int fd) {
+                // Anonymous mapping doesn't need resizing.
+                if (fd == -1) {
+                    return -1;
+                }
+
+                // Make sure the file backing this mapping is large enough.
+                if (osmium::util::file_size(fd) < m_size + m_offset) {
+                    osmium::util::resize_file(fd, m_size + m_offset);
+                }
+                return fd;
+            }
+
+        public:
+
+            /**
+             * Create memory mapping of given size.
+             *
+             * If fd is not set (or fd == -1), an anonymous mapping will be
+             * created, otherwise a mapping based on the file descriptor will
+             * be created.
+             *
+             * @pre size > 0 or mode == write_shared oder write_private
+             *
+             * @param size Size of the mapping in bytes
+             * @param mode Mapping mode: readonly, or writable (shared or private)
+             * @param fd Open file descriptor of a file we want to map
+             * @param offset Offset into the file where the mapping should start
+             * @throws std::system_error if the mapping fails
+             */
+            MemoryMapping(size_t size, mapping_mode mode, int fd=-1, off_t offset=0);
+
+            /// DEPRECATED: For backwards compatibility
+            MemoryMapping(size_t size, bool writable=true, int fd=-1, off_t offset=0) :
+                MemoryMapping(size, writable ? mapping_mode::write_shared : mapping_mode::readonly, fd, offset)  {
+            }
+
+            /// You can not copy construct a MemoryMapping.
+            MemoryMapping(const MemoryMapping&) = delete;
+
+            /// You can not copy a MemoryMapping.
+            MemoryMapping& operator=(const MemoryMapping&) = delete;
+
+            /**
+             * Move construct a mapping from another one. The other mapping
+             * will be marked as invalid.
+             */
+            MemoryMapping(MemoryMapping&& other);
+
+            /**
+             * Move a mapping. The other mapping will be marked as invalid.
+             */
+            MemoryMapping& operator=(MemoryMapping&& other);
+
+            /**
+             * Releases the mapping by calling unmap(). Will never throw.
+             * Call unmap() instead if you want to be notified of any error.
+             */
+            ~MemoryMapping() noexcept {
+                try {
+                    unmap();
+                } catch (std::system_error&) {
+                    // Ignore any exceptions because destructor must not throw.
+                }
+            }
+
+            /**
+             * Unmap a mapping. If the mapping is not valid, it will do
+             * nothing.
+             *
+             * @throws std::system_error if the unmapping fails
+             */
+            void unmap();
+
+            /**
+             * Resize a mapping to the given new size.
+             *
+             * On Linux systems this will use the mremap() function. On other
+             * systems it will unmap and remap the memory. This can only be
+             * done for file-based mappings, not anonymous mappings!
+             *
+             * @param new_size Number of bytes to resize to
+             * @throws std::system_error if the remapping fails
+             */
+            void resize(size_t new_size);
+
+            /**
+             * In a boolean context a MemoryMapping is true when it is a valid
+             * existing mapping.
+             */
+            operator bool() const noexcept {
+                return is_valid();
+            }
+
+            /**
+             * The number of bytes mapped. This is the same size you created
+             * the mapping with. The actual mapping will probably be larger
+             * because the system will round it to the page size.
+             */
+            size_t size() const noexcept {
+                return m_size;
+            }
+
+            /**
+             * The file descriptor this mapping was created from.
+             *
+             * @returns file descriptor, -1 for anonymous mappings
+             */
+            int fd() const noexcept {
+                return m_fd;
+            }
+
+            /**
+             * Was this mapping created as a writable mapping?
+             */
+            bool writable() const noexcept {
+                return m_mapping_mode != mapping_mode::readonly;
+            }
+
+            /**
+             * Get the address of the mapping as any pointer type you like.
+             *
+             * @throws std::runtime_error if the mapping is invalid
+             */
+            template <typename T = void>
+            T* get_addr() const {
+                if (is_valid()) {
+                    return reinterpret_cast<T*>(m_addr);
+                }
+                throw std::runtime_error("invalid memory mapping");
+            }
+
+        }; // class MemoryMapping
+
+        /**
+         * Anonymous memory mapping.
+         *
+         * Usage for anonymous mapping:
+         * @code
+         * AnonymousMemoryMapping mapping(1024); // create anonymous mapping with size
+         * auto ptr = mapping.get_addr<char*>(); // get pointer to memory
+         * mapping.unmap();                      // release mapping by calling unmap() (or at end of scope)
+         * @endcode
+         */
+        class AnonymousMemoryMapping : public MemoryMapping {
+
+        public:
+
+            AnonymousMemoryMapping(size_t size) :
+                MemoryMapping(size, mapping_mode::write_private) {
+            }
+
+#ifndef __linux__
+            /**
+             * On systems other than Linux anonymous mappings can not be
+             * resized!
+             */
+            void resize(size_t) = delete;
+#endif
+
+        }; // class AnonymousMemoryMapping
+
+        /**
+         * A thin wrapper around the MemoryMapping class used when all the
+         * data in the mapped memory is of the same type. Instead of thinking
+         * about the number of bytes mapped, this counts sizes in the number
+         * of objects of that type.
+         *
+         * Note that no effort is made to actually initialize the objects in
+         * this memory. This has to be done by the caller!
+         */
+        template <typename T>
+        class TypedMemoryMapping {
+
+            MemoryMapping m_mapping;
+
+        public:
+
+            /**
+             * Create anonymous typed memory mapping of given size.
+             *
+             * @param size Number of objects of type T to be mapped
+             * @throws std::system_error if the mapping fails
+             */
+            TypedMemoryMapping(size_t size) :
+                m_mapping(sizeof(T) * size, MemoryMapping::mapping_mode::write_private) {
+            }
+
+            /**
+             * Create file-backed memory mapping of given size. The file must
+             * contain at least `sizeof(T) * size` bytes!
+             *
+             * @param size Number of objects of type T to be mapped
+             * @param mode Mapping mode: readonly, or writable (shared or private)
+             * @param fd Open file descriptor of a file we want to map
+             * @param offset Offset into the file where the mapping should start
+             * @throws std::system_error if the mapping fails
+             */
+            TypedMemoryMapping(size_t size, MemoryMapping::mapping_mode mode, int fd, off_t offset = 0) :
+                m_mapping(sizeof(T) * size, mode, fd, sizeof(T) * offset) {
+            }
+
+            /// DEPRECATED: For backwards compatibility
+            TypedMemoryMapping(size_t size, bool writable, int fd, off_t offset = 0) :
+                m_mapping(sizeof(T) * size, writable ? MemoryMapping::mapping_mode::write_shared : MemoryMapping::mapping_mode::readonly, fd, sizeof(T) * offset) {
+            }
+
+            /// You can not copy construct a TypedMemoryMapping.
+            TypedMemoryMapping(const TypedMemoryMapping&) = delete;
+
+            /// You can not copy a MemoryMapping.
+            TypedMemoryMapping& operator=(const TypedMemoryMapping&) = delete;
+
+            /**
+             * Move construct a mapping from another one. The other mapping
+             * will be marked as invalid.
+             */
+            TypedMemoryMapping(TypedMemoryMapping&& other) = default;
+
+            /**
+             * Move a mapping. The other mapping will be marked as invalid.
+             */
+            TypedMemoryMapping& operator=(TypedMemoryMapping&& other) = default;
+
+            /**
+             * Releases the mapping by calling unmap(). Will never throw.
+             * Call unmap() instead if you want to be notified of any error.
+             */
+            ~TypedMemoryMapping() noexcept = default;
+
+            /**
+             * Unmap a mapping. If the mapping is not valid, it will do
+             * nothing.
+             *
+             * @throws std::system_error if the unmapping fails
+             */
+            void unmap() {
+                m_mapping.unmap();
+            }
+
+            /**
+             * Resize a mapping to the given new size.
+             *
+             * On Linux systems this will use the mremap() function. On other
+             * systems it will unmap and remap the memory. This can only be
+             * done for file-based mappings, not anonymous mappings!
+             *
+             * @param new_size Number of objects of type T to resize to
+             * @throws std::system_error if the remapping fails
+             */
+            void resize(size_t new_size) {
+                m_mapping.resize(sizeof(T) * new_size);
+            }
+
+            /**
+             * In a boolean context a TypedMemoryMapping is true when it is
+             * a valid existing mapping.
+             */
+            operator bool() const noexcept {
+                return !!m_mapping;
+            }
+
+            /**
+             * The number of objects of class T mapped. This is the same size
+             * you created the mapping with. The actual mapping will probably
+             * be larger because the system will round it to the page size.
+             */
+            size_t size() const noexcept {
+                assert(m_mapping.size() % sizeof(T) == 0);
+                return m_mapping.size() / sizeof(T);
+            }
+
+            /**
+             * The file descriptor this mapping was created from.
+             *
+             * @returns file descriptor, -1 for anonymous mappings
+             */
+            int fd() const noexcept {
+                return m_mapping.fd();
+            }
+
+            /**
+             * Was this mapping created as a writable mapping?
+             */
+            bool writable() const noexcept {
+                return m_mapping.writable();
+            }
+
+            /**
+             * Get the address of the beginning of the mapping.
+             *
+             * @throws std::runtime_error if the mapping is invalid
+             */
+            T* begin() {
+                return m_mapping.get_addr<T>();
+            }
+
+            /**
+             * Get the address one past the end of the mapping.
+             *
+             * @throws std::runtime_error if the mapping is invalid
+             */
+            T* end() {
+                return m_mapping.get_addr<T>() + size();
+            }
+
+            const T* cbegin() const {
+                return m_mapping.get_addr<T>();
+            }
+
+            const T* cend() const {
+                return m_mapping.get_addr<T>() + size();
+            }
+
+            const T* begin() const {
+                return m_mapping.get_addr<T>();
+            }
+
+            const T* end() const {
+                return m_mapping.get_addr<T>() + size();
+            }
+
+        }; // class TypedMemoryMapping
+
+        template <typename T>
+        class AnonymousTypedMemoryMapping : public TypedMemoryMapping<T> {
+
+        public:
+
+            AnonymousTypedMemoryMapping(size_t size) :
+                TypedMemoryMapping<T>(size) {
+            }
+
+#ifndef __linux__
+            /**
+             * On systems other than Linux anonymous mappings can not be
+             * resized!
+             */
+            void resize(size_t) = delete;
+#endif
+
+        }; // class AnonymousTypedMemoryMapping
+
+    } // namespace util
+
+} // namespace osmium
+
+#ifndef _WIN32
+
+// =========== Unix implementation =============
+
+// MAP_FAILED is often a macro containing an old style cast
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+
+inline bool osmium::util::MemoryMapping::is_valid() const noexcept {
+    return m_addr != MAP_FAILED;
+}
+
+inline void osmium::util::MemoryMapping::make_invalid() noexcept {
+    m_addr = MAP_FAILED;
+}
+
+#pragma GCC diagnostic pop
+
+// for BSD systems
+#ifndef MAP_ANONYMOUS
+# define MAP_ANONYMOUS MAP_ANON
+#endif
+
+inline int osmium::util::MemoryMapping::get_protection() const noexcept {
+    if (m_mapping_mode == mapping_mode::readonly) {
+        return PROT_READ;
+    }
+    return PROT_READ | PROT_WRITE;
+}
+
+inline int osmium::util::MemoryMapping::get_flags() const noexcept {
+    if (m_fd == -1) {
+        return MAP_PRIVATE | MAP_ANONYMOUS;
+    }
+    if (m_mapping_mode == mapping_mode::write_shared) {
+        return MAP_SHARED;
+    }
+    return MAP_PRIVATE;
+}
+
+inline osmium::util::MemoryMapping::MemoryMapping(size_t size, mapping_mode mode, int fd, off_t offset) :
+    m_size(initial_size(size)),
+    m_offset(offset),
+    m_fd(resize_fd(fd)),
+    m_mapping_mode(mode),
+    m_addr(::mmap(nullptr, m_size, get_protection(), get_flags(), m_fd, m_offset)) {
+    assert(!(fd == -1 && mode == mapping_mode::readonly));
+    if (!is_valid()) {
+        throw std::system_error(errno, std::system_category(), "mmap failed");
+    }
+}
+
+inline osmium::util::MemoryMapping::MemoryMapping(MemoryMapping&& other) :
+    m_size(other.m_size),
+    m_offset(other.m_offset),
+    m_fd(other.m_fd),
+    m_mapping_mode(other.m_mapping_mode),
+    m_addr(other.m_addr) {
+    other.make_invalid();
+}
+
+inline osmium::util::MemoryMapping& osmium::util::MemoryMapping::operator=(osmium::util::MemoryMapping&& other) {
+    unmap();
+    m_size         = other.m_size;
+    m_offset       = other.m_offset;
+    m_fd           = other.m_fd;
+    m_mapping_mode = other.m_mapping_mode;
+    m_addr         = other.m_addr;
+    other.make_invalid();
+    return *this;
+}
+
+inline void osmium::util::MemoryMapping::unmap() {
+    if (is_valid()) {
+        if (::munmap(m_addr, m_size) != 0) {
+            throw std::system_error(errno, std::system_category(), "munmap failed");
+        }
+        make_invalid();
+    }
+}
+
+inline void osmium::util::MemoryMapping::resize(size_t new_size) {
+    assert(new_size > 0 && "can not resize to zero size");
+    if (m_fd == -1) { // anonymous mapping
+#ifdef __linux__
+        m_addr = ::mremap(m_addr, m_size, new_size, MREMAP_MAYMOVE);
+        if (!is_valid()) {
+            throw std::system_error(errno, std::system_category(), "mremap failed");
+        }
+        m_size = new_size;
+#else
+        assert(false && "can't resize anonymous mappings on non-linux systems");
+#endif
+    } else { // file-based mapping
+        unmap();
+        m_size = new_size;
+        resize_fd(m_fd);
+        m_addr = ::mmap(nullptr, new_size, get_protection(), get_flags(), m_fd, m_offset);
+        if (!is_valid()) {
+            throw std::system_error(errno, std::system_category(), "mmap (remap) failed");
+        }
+    }
+}
+
+#else
+
+// =========== Windows implementation =============
+
+/* References:
+ * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
+ * CloseHandle:       http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
+ * MapViewOfFile:     http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx
+ * UnmapViewOfFile:   http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx
+ */
+
+namespace osmium {
+
+    namespace util {
+
+        inline DWORD dword_hi(uint64_t x) {
+            return static_cast<DWORD>(x >> 32);
+        }
+
+        inline DWORD dword_lo(uint64_t x) {
+            return static_cast<DWORD>(x & 0xffffffff);
+        }
+
+    } // namespace util
+
+} // namespace osmium
+
+inline DWORD osmium::util::MemoryMapping::get_protection() const noexcept {
+    switch (m_mapping_mode) {
+        case mapping_mode::readonly:
+            return PAGE_READONLY;
+        case mapping_mode::write_private:
+            return PAGE_WRITECOPY;
+        case mapping_mode::write_shared:
+            return PAGE_READWRITE;
+    }
+}
+
+inline DWORD osmium::util::MemoryMapping::get_flags() const noexcept {
+    switch (m_mapping_mode) {
+        case mapping_mode::readonly:
+            return FILE_MAP_READ;
+        case mapping_mode::write_private:
+            return FILE_MAP_COPY;
+        case mapping_mode::write_shared:
+            return FILE_MAP_WRITE;
+    }
+}
+
+inline HANDLE osmium::util::MemoryMapping::get_handle() const noexcept {
+    if (m_fd == -1) {
+        return INVALID_HANDLE_VALUE;
+    }
+    return reinterpret_cast<HANDLE>(_get_osfhandle(m_fd));
+}
+
+inline HANDLE osmium::util::MemoryMapping::create_file_mapping() const noexcept {
+    if (m_fd != -1) {
+        _setmode(m_fd, _O_BINARY);
+    }
+    return CreateFileMapping(get_handle(), nullptr, get_protection(), osmium::util::dword_hi(static_cast<uint64_t>(m_size) + m_offset), osmium::util::dword_lo(static_cast<uint64_t>(m_size) + m_offset), nullptr);
+}
+
+inline void* osmium::util::MemoryMapping::map_view_of_file() const noexcept {
+    return MapViewOfFile(m_handle, get_flags(), osmium::util::dword_hi(m_offset), osmium::util::dword_lo(m_offset), m_size);
+}
+
+inline bool osmium::util::MemoryMapping::is_valid() const noexcept {
+    return m_addr != nullptr;
+}
+
+inline void osmium::util::MemoryMapping::make_invalid() noexcept {
+    m_addr = nullptr;
+}
+
+inline osmium::util::MemoryMapping::MemoryMapping(size_t size, MemoryMapping::mapping_mode mode, int fd, off_t offset) :
+    m_size(initial_size(size)),
+    m_offset(offset),
+    m_fd(resize_fd(fd)),
+    m_mapping_mode(mode),
+    m_handle(create_file_mapping()),
+    m_addr(nullptr) {
+
+    if (!m_handle) {
+        throw std::system_error(GetLastError(), std::system_category(), "CreateFileMapping failed");
+    }
+
+    m_addr = map_view_of_file();
+    if (!is_valid()) {
+        throw std::system_error(GetLastError(), std::system_category(), "MapViewOfFile failed");
+    }
+}
+
+inline osmium::util::MemoryMapping::MemoryMapping(MemoryMapping&& other) :
+    m_size(other.m_size),
+    m_offset(other.m_offset),
+    m_fd(other.m_fd),
+    m_mapping_mode(other.m_mapping_mode),
+    m_handle(std::move(other.m_handle)),
+    m_addr(other.m_addr) {
+    other.make_invalid();
+    other.m_handle = nullptr;
+}
+
+inline osmium::util::MemoryMapping& osmium::util::MemoryMapping::operator=(osmium::util::MemoryMapping&& other) {
+    unmap();
+    m_size         = other.m_size;
+    m_offset       = other.m_offset;
+    m_fd           = other.m_fd;
+    m_mapping_mode = other.m_mapping_mode;
+    m_handle       = std::move(other.m_handle);
+    m_addr         = other.m_addr;
+    other.make_invalid();
+    other.m_handle = nullptr;
+    return *this;
+}
+
+inline void osmium::util::MemoryMapping::unmap() {
+    if (is_valid()) {
+        if (! UnmapViewOfFile(m_addr)) {
+            throw std::system_error(GetLastError(), std::system_category(), "UnmapViewOfFile failed");
+        }
+        make_invalid();
+    }
+
+    if (m_handle) {
+        if (! CloseHandle(m_handle)) {
+            throw std::system_error(GetLastError(), std::system_category(), "CloseHandle failed");
+        }
+        m_handle = nullptr;
+    }
+}
+
+inline void osmium::util::MemoryMapping::resize(size_t new_size) {
+    unmap();
+
+    m_size = new_size;
+    resize_fd(m_fd);
+
+    m_handle = create_file_mapping();
+    if (!m_handle) {
+        throw std::system_error(GetLastError(), std::system_category(), "CreateFileMapping failed");
+    }
+
+    m_addr = map_view_of_file();
+    if (!is_valid()) {
+        throw std::system_error(GetLastError(), std::system_category(), "MapViewOfFile failed");
+    }
+}
+
+#endif
+
+#endif // OSMIUM_UTIL_MEMORY_MAPPING_HPP
diff --git a/contrib/libosmium/osmium/util/minmax.hpp b/contrib/libosmium/osmium/util/minmax.hpp
new file mode 100644
index 0000000..2eb601a
--- /dev/null
+++ b/contrib/libosmium/osmium/util/minmax.hpp
@@ -0,0 +1,120 @@
+#ifndef OSMIUM_UTIL_MINMAX_HPP
+#define OSMIUM_UTIL_MINMAX_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <limits>
+
+namespace osmium {
+
+    template <typename T>
+    inline T min_op_start_value() {
+         return std::numeric_limits<T>::max();
+    }
+
+    /**
+     * Class for calculating the minimum of a bunch of values.
+     * Works with any numeric type.
+     *
+     * Usage:
+     *
+     *    min_op<int> x;
+     *    x.update(27);
+     *    x.update(12);
+     *    auto min = x.get(); // 12
+     */
+    template <typename T>
+    class min_op {
+
+        T m_value;
+
+    public:
+
+        explicit min_op(T start_value = min_op_start_value<T>()) :
+            m_value(start_value) {
+        }
+
+        void update(T value) noexcept {
+            if (value < m_value) {
+                m_value = value;
+            }
+        }
+
+        T operator()() const noexcept {
+            return m_value;
+        }
+
+    };
+
+    template <typename T>
+    inline T max_op_start_value() {
+         return std::numeric_limits<T>::min();
+    }
+
+    /**
+     * Class for calculating the maximum of a bunch of values.
+     * Works with any numeric type.
+     *
+     * Usage:
+     *
+     *    max_op<int> x;
+     *    x.update(27);
+     *    x.update(12);
+     *    auto max = x.get(); // 27
+     */
+    template <typename T>
+    class max_op {
+
+        T m_value;
+
+    public:
+
+        explicit max_op(T start_value = max_op_start_value<T>()) :
+            m_value(start_value) {
+        }
+
+        void update(T value) noexcept {
+            if (value > m_value) {
+                m_value = value;
+            }
+        }
+
+        T operator()() const noexcept {
+            return m_value;
+        }
+
+    };
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_MINMAX_HPP
diff --git a/contrib/libosmium/osmium/util/options.hpp b/contrib/libosmium/osmium/util/options.hpp
new file mode 100644
index 0000000..24c0918
--- /dev/null
+++ b/contrib/libosmium/osmium/util/options.hpp
@@ -0,0 +1,165 @@
+#ifndef OSMIUM_UTIL_OPTIONS_HPP
+#define OSMIUM_UTIL_OPTIONS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <initializer_list>
+#include <map>
+#include <string>
+#include <utility>
+
+namespace osmium {
+
+    namespace util {
+
+        /**
+         * Stores key=value type options. This class can be used stand-alone or
+         * as a base class. Options are stored and retrieved by key using the
+         * different set() and get() methods.
+         *
+         * You can iterate over all set options. Dereferencing an iterator
+         * yields a std::pair of the key and value strings.
+         */
+        class Options {
+
+            typedef std::map<std::string, std::string> option_map;
+            option_map m_options;
+
+        public:
+
+            typedef option_map::iterator iterator;
+            typedef option_map::const_iterator const_iterator;
+            typedef option_map::value_type value_type;
+
+            Options() = default;
+
+            explicit Options(const std::initializer_list<value_type>& values) :
+                m_options(values) {
+            }
+
+            Options(const Options&) = default;
+            Options& operator=(const Options&) = default;
+
+            Options(Options&&) = default;
+            Options& operator=(Options&&) = default;
+
+            ~Options() = default;
+
+            void set(const std::string& key, const std::string& value) {
+                m_options[key] = value;
+            }
+
+            void set(const std::string& key, const char* value) {
+                m_options[key] = value;
+            }
+
+            void set(const std::string& key, bool value) {
+                m_options[key] = value ? "true" : "false";
+            }
+
+            void set(std::string data) {
+                size_t pos = data.find_first_of('=');
+                if (pos == std::string::npos) {
+                    m_options[data] = "true";
+                } else {
+                    std::string value = data.substr(pos+1);
+                    data.erase(pos);
+                    set(data, value);
+                }
+            }
+
+            /**
+             * Get value of "key" option. If not set the default_value (or
+             * empty string) is returned.
+             */
+            std::string get(const std::string& key, const std::string& default_value="") const noexcept {
+                auto it = m_options.find(key);
+                if (it == m_options.end()) {
+                    return default_value;
+                }
+                return it->second;
+            }
+
+            /**
+             * Is this option set to a true value ("true" or "yes")?
+             * Will return false if the value is unset.
+             */
+            bool is_true(const std::string& key) const noexcept {
+                std::string value = get(key);
+                return (value == "true" || value == "yes");
+            }
+
+            /**
+             * Is this option not set to a false value ("false" or "no")?
+             * Will return true if the value is unset.
+             */
+            bool is_not_false(const std::string& key) const noexcept {
+                std::string value = get(key);
+                return !(value == "false" || value == "no");
+            }
+
+            size_t size() const noexcept {
+                return m_options.size();
+            }
+
+            iterator begin() noexcept {
+                return m_options.begin();
+            }
+
+            iterator end() noexcept {
+                return m_options.end();
+            }
+
+            const_iterator begin() const noexcept {
+                return m_options.cbegin();
+            }
+
+            const_iterator end() const noexcept {
+                return m_options.cend();
+            }
+
+            const_iterator cbegin() const noexcept {
+                return m_options.cbegin();
+            }
+
+            const_iterator cend() const noexcept {
+                return m_options.cend();
+            }
+
+        }; // class Options
+
+    } // namespace util
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_OPTIONS_HPP
diff --git a/contrib/libosmium/osmium/util/string.hpp b/contrib/libosmium/osmium/util/string.hpp
new file mode 100644
index 0000000..55bfc6c
--- /dev/null
+++ b/contrib/libosmium/osmium/util/string.hpp
@@ -0,0 +1,102 @@
+#ifndef OSMIUM_UTIL_STRING_HPP
+#define OSMIUM_UTIL_STRING_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <string>
+#include <vector>
+#include <iostream>
+
+namespace osmium {
+
+    /**
+     * Split string on the separator character.
+     *
+     * @param str The string to be split.
+     * @param sep The separator character.
+     * @param compact Set this to true to remove empty strings from result
+     * @returns Vector with the parts of the string split up.
+     */
+    inline std::vector<std::string> split_string(const std::string& str, const char sep, bool compact = false) {
+        std::vector<std::string> tokens;
+
+        if (!str.empty()) {
+            size_t pos = 0;
+            size_t nextpos = str.find_first_of(sep);
+            while (nextpos != std::string::npos) {
+                if (!compact || (nextpos - pos != 0)) {
+                    tokens.push_back(str.substr(pos, nextpos-pos));
+                }
+                pos = nextpos + 1;
+                nextpos = str.find_first_of(sep, pos);
+            }
+            if (!compact || pos != str.size()) {
+                tokens.push_back(str.substr(pos));
+            }
+        }
+
+        return tokens;
+    }
+
+    /**
+     * Split string on the separator character(s).
+     *
+     * @param str The string to be split.
+     * @param sep The separator character(s).
+     * @param compact Set this to true to remove empty strings from result
+     * @returns Vector with the parts of the string split up.
+     */
+    inline std::vector<std::string> split_string(const std::string& str, const char* sep, bool compact = false) {
+        std::vector<std::string> tokens;
+
+        if (!str.empty()) {
+            size_t pos = 0;
+            size_t nextpos = str.find_first_of(sep);
+            while (nextpos != std::string::npos) {
+                if (!compact || (nextpos - pos != 0)) {
+                    tokens.push_back(str.substr(pos, nextpos-pos));
+                }
+                pos = nextpos + 1;
+                nextpos = str.find_first_of(sep, pos);
+            }
+            if (!compact || pos != str.size()) {
+                tokens.push_back(str.substr(pos));
+            }
+        }
+
+        return tokens;
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_STRING_HPP
diff --git a/contrib/libosmium/osmium/util/verbose_output.hpp b/contrib/libosmium/osmium/util/verbose_output.hpp
new file mode 100644
index 0000000..249d67f
--- /dev/null
+++ b/contrib/libosmium/osmium/util/verbose_output.hpp
@@ -0,0 +1,139 @@
+#ifndef OSMIUM_UTIL_VERBOSE_OUTPUT_HPP
+#define OSMIUM_UTIL_VERBOSE_OUTPUT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <time.h>
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+namespace osmium {
+
+    /**
+     * @brief Helpful utility classes and functions not strictly OSM related
+     */
+    namespace util {
+
+        /**
+         * Osmium programs often run for a long time because of the amount of
+         * OSM data processed. This class helps with keeping the user up to
+         * date by offering an easy way for programs to optionally output
+         * verbose information about what's going on.
+         *
+         * Use an object of this class instead of std::cerr as an output
+         * stream. Nothing is actually written if the object is not set to
+         * verbose mode. If it is set to verbose mode, each line is prepended
+         * with the running time, ie the time since the VerboseOutput object
+         * was created.
+         */
+        class VerboseOutput {
+
+            /// all time output will be relative to this start time
+            time_t m_start;
+
+            /// is verbose mode enabled?
+            bool m_verbose;
+
+            /// a newline was written, start next output with runtime
+            bool m_newline;
+
+            /**
+             * If we remember that a newline was written as the last thing
+             * write out the time elapsed and reset the newline flag.
+             */
+            void start_line() {
+                if (m_newline) {
+                    time_t elapsed = runtime();
+
+                    char old_fill = std::cerr.fill();
+                    std::cerr << '[' << std::setw(2) << (elapsed / 60) << ':' << std::setw(2) << std::setfill('0') << (elapsed % 60) << "] ";
+                    std::cerr.fill(old_fill);
+
+                    m_newline = false;
+                }
+            }
+
+        public:
+
+            explicit VerboseOutput(bool verbose = false) noexcept :
+                m_start(time(NULL)),
+                m_verbose(verbose),
+                m_newline(true) {
+            }
+
+            ~VerboseOutput() = default;
+
+            VerboseOutput(const VerboseOutput&) = default;
+            VerboseOutput& operator=(const VerboseOutput&) = default;
+            VerboseOutput(VerboseOutput&&) = default;
+            VerboseOutput& operator=(VerboseOutput&&) = default;
+
+            time_t runtime() const noexcept {
+                return time(NULL) - m_start;
+            }
+
+            /// Get "verbose" setting.
+            bool verbose() const noexcept {
+                return m_verbose;
+            }
+
+            /// Set "verbose" setting.
+            void verbose(bool verbose) noexcept {
+                m_verbose = verbose;
+            }
+
+            template<typename T>
+            friend VerboseOutput& operator<<(VerboseOutput& verbose_output, const T& value) {
+                if (verbose_output.m_verbose) {
+                    verbose_output.start_line();
+                    std::cerr << value;
+
+                    // check if there was a newline a the end and remember that
+                    std::ostringstream output_buffer;
+                    output_buffer << value;
+                    if (!output_buffer.str().empty() && output_buffer.str().back() == '\n') {
+                        verbose_output.m_newline = true;
+                    }
+                }
+                return verbose_output;
+            }
+
+        }; // class VerboseOutput
+
+    } // namespace util
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_VERBOSE_OUTPUT_HPP
diff --git a/contrib/libosmium/osmium/visitor.hpp b/contrib/libosmium/osmium/visitor.hpp
new file mode 100644
index 0000000..35fcb4e
--- /dev/null
+++ b/contrib/libosmium/osmium/visitor.hpp
@@ -0,0 +1,258 @@
+#ifndef OSMIUM_VISITOR_HPP
+#define OSMIUM_VISITOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <type_traits>
+
+#include <osmium/io/reader_iterator.hpp> // IWYU pragma: keep
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/entity.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+    class TagList;
+    class WayNodeList;
+    class RelationMemberList;
+    class OuterRing;
+    class InnerRing;
+
+    namespace memory {
+        class Item;
+    }
+
+    namespace detail {
+
+        template <typename T, typename U>
+        using ConstIfConst = typename std::conditional<std::is_const<T>::value, typename std::add_const<U>::type, U>::type;
+
+        template <typename THandler, typename TItem>
+        inline void apply_item_recurse(TItem& item, THandler& handler) {
+            switch (item.type()) {
+                case osmium::item_type::undefined:
+                    break;
+                case osmium::item_type::node:
+                    handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+                    handler.node(static_cast<ConstIfConst<TItem, osmium::Node>&>(item));
+                    break;
+                case osmium::item_type::way:
+                    handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+                    handler.way(static_cast<ConstIfConst<TItem, osmium::Way>&>(item));
+                    break;
+                case osmium::item_type::relation:
+                    handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+                    handler.relation(static_cast<ConstIfConst<TItem, osmium::Relation>&>(item));
+                    break;
+                case osmium::item_type::area:
+                    handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+                    handler.area(static_cast<ConstIfConst<TItem, osmium::Area>&>(item));
+                    break;
+                case osmium::item_type::changeset:
+                    handler.changeset(static_cast<ConstIfConst<TItem, osmium::Changeset>&>(item));
+                    break;
+                case osmium::item_type::tag_list:
+                    handler.tag_list(static_cast<ConstIfConst<TItem, osmium::TagList>&>(item));
+                    break;
+                case osmium::item_type::way_node_list:
+                    handler.way_node_list(static_cast<ConstIfConst<TItem, osmium::WayNodeList>&>(item));
+                    break;
+                case osmium::item_type::relation_member_list:
+                case osmium::item_type::relation_member_list_with_full_members:
+                    handler.relation_member_list(static_cast<ConstIfConst<TItem, osmium::RelationMemberList>&>(item));
+                    break;
+                case osmium::item_type::outer_ring:
+                    handler.outer_ring(static_cast<ConstIfConst<TItem, osmium::OuterRing>&>(item));
+                    break;
+                case osmium::item_type::inner_ring:
+                    handler.inner_ring(static_cast<ConstIfConst<TItem, osmium::InnerRing>&>(item));
+                    break;
+                case osmium::item_type::changeset_discussion:
+                    handler.changeset_discussion(static_cast<ConstIfConst<TItem, osmium::ChangesetDiscussion>&>(item));
+                    break;
+            }
+        }
+
+        template <typename THandler>
+        inline void apply_item_recurse(const osmium::OSMEntity& item, THandler& handler) {
+            switch (item.type()) {
+                case osmium::item_type::node:
+                    handler.osm_object(static_cast<const osmium::OSMObject&>(item));
+                    handler.node(static_cast<const osmium::Node&>(item));
+                    break;
+                case osmium::item_type::way:
+                    handler.osm_object(static_cast<const osmium::OSMObject&>(item));
+                    handler.way(static_cast<const osmium::Way&>(item));
+                    break;
+                case osmium::item_type::relation:
+                    handler.osm_object(static_cast<const osmium::OSMObject&>(item));
+                    handler.relation(static_cast<const osmium::Relation&>(item));
+                    break;
+                case osmium::item_type::area:
+                    handler.osm_object(static_cast<const osmium::OSMObject&>(item));
+                    handler.area(static_cast<const osmium::Area&>(item));
+                    break;
+                case osmium::item_type::changeset:
+                    handler.changeset(static_cast<const osmium::Changeset&>(item));
+                    break;
+                default:
+                    throw osmium::unknown_type();
+            }
+        }
+
+        template <typename THandler>
+        inline void apply_item_recurse(osmium::OSMEntity& item, THandler& handler) {
+            switch (item.type()) {
+                case osmium::item_type::node:
+                    handler.osm_object(static_cast<osmium::OSMObject&>(item));
+                    handler.node(static_cast<osmium::Node&>(item));
+                    break;
+                case osmium::item_type::way:
+                    handler.osm_object(static_cast<osmium::OSMObject&>(item));
+                    handler.way(static_cast<osmium::Way&>(item));
+                    break;
+                case osmium::item_type::relation:
+                    handler.osm_object(static_cast<osmium::OSMObject&>(item));
+                    handler.relation(static_cast<osmium::Relation&>(item));
+                    break;
+                case osmium::item_type::area:
+                    handler.osm_object(static_cast<osmium::OSMObject&>(item));
+                    handler.area(static_cast<osmium::Area&>(item));
+                    break;
+                case osmium::item_type::changeset:
+                    handler.changeset(static_cast<osmium::Changeset&>(item));
+                    break;
+                default:
+                    throw osmium::unknown_type();
+            }
+        }
+
+        template <typename THandler>
+        inline void apply_item_recurse(const osmium::OSMObject& item, THandler& handler) {
+            switch (item.type()) {
+                case osmium::item_type::node:
+                    handler.osm_object(item);
+                    handler.node(static_cast<const osmium::Node&>(item));
+                    break;
+                case osmium::item_type::way:
+                    handler.osm_object(item);
+                    handler.way(static_cast<const osmium::Way&>(item));
+                    break;
+                case osmium::item_type::relation:
+                    handler.osm_object(item);
+                    handler.relation(static_cast<const osmium::Relation&>(item));
+                    break;
+                case osmium::item_type::area:
+                    handler.osm_object(item);
+                    handler.area(static_cast<const osmium::Area&>(item));
+                    break;
+                default:
+                    throw osmium::unknown_type();
+            }
+        }
+
+        template <typename THandler>
+        inline void apply_item_recurse(osmium::OSMObject& item, THandler& handler) {
+            switch (item.type()) {
+                case osmium::item_type::node:
+                    handler.osm_object(item);
+                    handler.node(static_cast<osmium::Node&>(item));
+                    break;
+                case osmium::item_type::way:
+                    handler.osm_object(item);
+                    handler.way(static_cast<osmium::Way&>(item));
+                    break;
+                case osmium::item_type::relation:
+                    handler.osm_object(item);
+                    handler.relation(static_cast<osmium::Relation&>(item));
+                    break;
+                case osmium::item_type::area:
+                    handler.osm_object(item);
+                    handler.area(static_cast<osmium::Area&>(item));
+                    break;
+                default:
+                    throw osmium::unknown_type();
+            }
+        }
+
+        template <typename THandler, typename TItem, typename... TRest>
+        inline void apply_item_recurse(TItem& item, THandler& handler, TRest&... more) {
+            apply_item_recurse(item, handler);
+            apply_item_recurse(item, more...);
+        }
+
+        template <typename THandler>
+        inline void flush_recurse(THandler& handler) {
+            handler.flush();
+        }
+
+        template <typename THandler, typename... TRest>
+        inline void flush_recurse(THandler& handler, TRest&... more) {
+            flush_recurse(handler);
+            flush_recurse(more...);
+        }
+
+    } // namespace detail
+
+    template <typename... THandlers>
+    inline void apply_item(const osmium::memory::Item& item, THandlers&... handlers) {
+        detail::apply_item_recurse(item, handlers...);
+    }
+
+    template <typename... THandlers>
+    inline void apply_item(osmium::memory::Item& item, THandlers&... handlers) {
+        detail::apply_item_recurse(item, handlers...);
+    }
+
+    template <typename TIterator, typename... THandlers>
+    inline void apply(TIterator it, TIterator end, THandlers&... handlers) {
+        for (; it != end; ++it) {
+            detail::apply_item_recurse(*it, handlers...);
+        }
+        detail::flush_recurse(handlers...);
+    }
+
+    template <typename TContainer, typename... THandlers>
+    inline void apply(TContainer& c, THandlers&... handlers) {
+        apply(std::begin(c), std::end(c), handlers...);
+    }
+
+    template <typename... THandlers>
+    inline void apply(const osmium::memory::Buffer& buffer, THandlers&... handlers) {
+        apply(buffer.cbegin(), buffer.cend(), handlers...);
+    }
+
+} // namespace osmium
+
+#endif // OSMIUM_VISITOR_HPP
diff --git a/contrib/libosmium/protozero/byteswap.hpp b/contrib/libosmium/protozero/byteswap.hpp
new file mode 100644
index 0000000..29c312a
--- /dev/null
+++ b/contrib/libosmium/protozero/byteswap.hpp
@@ -0,0 +1,69 @@
+#ifndef PROTOZERO_BYTESWAP_HPP
+#define PROTOZERO_BYTESWAP_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file byteswap.hpp
+ *
+ * @brief Contains functions to swap bytes in values (for different endianness).
+ */
+
+#include <cstdint>
+#include <cassert>
+
+namespace protozero {
+
+/**
+ * Swap N byte value between endianness formats. This template function must
+ * be specialized to actually work.
+ */
+template <int N>
+inline void byteswap(const char* /*data*/, char* /*result*/) {
+    static_assert(N == 1, "Can only swap 4 or 8 byte values");
+}
+
+/**
+ * Swap 4 byte value (int32_t, uint32_t, float) between endianness formats.
+ */
+template <>
+inline void byteswap<4>(const char* data, char* result) {
+# if defined(__GNUC__) || defined(__clang__)
+    *reinterpret_cast<uint32_t*>(result) = __builtin_bswap32(*reinterpret_cast<const uint32_t*>(data));
+# else
+    result[3] = data[0];
+    result[2] = data[1];
+    result[1] = data[2];
+    result[0] = data[3];
+#endif
+}
+
+/**
+ * Swap 8 byte value (int64_t, uint64_t, double) between endianness formats.
+ */
+template <>
+inline void byteswap<8>(const char* data, char* result) {
+# if defined(__GNUC__) || defined(__clang__)
+    *reinterpret_cast<uint64_t*>(result) = __builtin_bswap64(*reinterpret_cast<const uint64_t*>(data));
+# else
+    result[7] = data[0];
+    result[6] = data[1];
+    result[5] = data[2];
+    result[4] = data[3];
+    result[3] = data[4];
+    result[2] = data[5];
+    result[1] = data[6];
+    result[0] = data[7];
+#endif
+}
+
+} // end namespace protozero
+
+#endif // PROTOZERO_BYTESWAP_HPP
diff --git a/contrib/libosmium/protozero/exception.hpp b/contrib/libosmium/protozero/exception.hpp
new file mode 100644
index 0000000..1229f7d
--- /dev/null
+++ b/contrib/libosmium/protozero/exception.hpp
@@ -0,0 +1,68 @@
+#ifndef PROTOZERO_EXCEPTION_HPP
+#define PROTOZERO_EXCEPTION_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file exception.hpp
+ *
+ * @brief Contains the exceptions used in the protozero library.
+ */
+
+#include <exception>
+
+/**
+ * @brief All parts of the protozero header-only library are in this namespace.
+ */
+namespace protozero {
+
+/**
+ * All exceptions explicitly thrown by the functions of the protozero library
+ * derive from this exception.
+ */
+struct exception : std::exception {
+    /// Returns the explanatory string.
+    const char *what() const noexcept { return "pbf exception"; }
+};
+
+/**
+ * This exception is thrown when parsing a varint thats larger than allowed.
+ * This should never happen unless the data is corrupted.
+ */
+struct varint_too_long_exception : exception {
+    /// Returns the explanatory string.
+    const char *what() const noexcept { return "varint too long exception"; }
+};
+
+/**
+ * This exception is thrown when the wire type of a pdf field is unknown.
+ * This should never happen unless the data is corrupted.
+ */
+struct unknown_pbf_wire_type_exception : exception {
+    /// Returns the explanatory string.
+    const char *what() const noexcept { return "unknown pbf field type exception"; }
+};
+
+/**
+ * This exception is thrown when we are trying to read a field and there
+ * are not enough bytes left in the buffer to read it. Almost all functions
+ * of the pbf_reader class can throw this exception.
+ *
+ * This should never happen unless the data is corrupted or you have
+ * initialized the pbf_reader object with incomplete data.
+ */
+struct end_of_buffer_exception : exception {
+    /// Returns the explanatory string.
+    const char *what() const noexcept { return "end of buffer exception"; }
+};
+
+} // end namespace protozero
+
+#endif // PROTOZERO_EXCEPTION_HPP
diff --git a/contrib/libosmium/protozero/pbf_builder.hpp b/contrib/libosmium/protozero/pbf_builder.hpp
new file mode 100644
index 0000000..063fa9c
--- /dev/null
+++ b/contrib/libosmium/protozero/pbf_builder.hpp
@@ -0,0 +1,137 @@
+#ifndef PROTOZERO_PBF_BUILDER_HPP
+#define PROTOZERO_PBF_BUILDER_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file pbf_builder.hpp
+ *
+ * @brief Contains the pbf_builder template class.
+ */
+
+#include <type_traits>
+
+#include <protozero/pbf_types.hpp>
+#include <protozero/pbf_writer.hpp>
+
+namespace protozero {
+
+/**
+ * The pbf_builder is used to write PBF formatted messages into a buffer. It
+ * is based on the pbf_writer class and has all the same methods. The
+ * difference is that whereever the pbf_writer class takes an integer tag,
+ * this template class takes a tag of the template type T.
+ *
+ * Almost all methods in this class can throw an std::bad_alloc exception if
+ * the std::string used as a buffer wants to resize.
+ *
+ * Read the tutorial to understand how this class is used.
+ */
+template <typename T>
+class pbf_builder : public pbf_writer {
+
+    static_assert(std::is_same<pbf_tag_type, typename std::underlying_type<T>::type>::value,
+                  "T must be enum with underlying type protozero::pbf_tag_type");
+
+public:
+
+    using enum_type = T;
+
+    pbf_builder(std::string& data) noexcept :
+        pbf_writer(data) {
+    }
+
+    template <typename P>
+    pbf_builder(pbf_writer& parent_writer, P tag) noexcept :
+        pbf_writer(parent_writer, pbf_tag_type(tag)) {
+    }
+
+/// @cond INTERNAL
+#define PROTOZERO_WRITER_WRAP_ADD_SCALAR(name, type) \
+    inline void add_##name(T tag, type value) { \
+        pbf_writer::add_##name(pbf_tag_type(tag), value); \
+    }
+
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(bool, bool)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(enum, int32_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(int32, int32_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint32, int32_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint32, uint32_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(int64, int64_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint64, int64_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint64, uint64_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed32, uint32_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed32, int32_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed64, uint64_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed64, int64_t)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(float, float)
+    PROTOZERO_WRITER_WRAP_ADD_SCALAR(double, double)
+
+#undef PROTOZERO_WRITER_WRAP_ADD_SCALAR
+/// @endcond
+
+    inline void add_bytes(T tag, const char* value, size_t size) {
+        pbf_writer::add_bytes(pbf_tag_type(tag), value, size);
+    }
+
+    inline void add_bytes(T tag, const std::string& value) {
+        pbf_writer::add_bytes(pbf_tag_type(tag), value);
+    }
+
+    inline void add_string(T tag, const char* value, size_t size) {
+        pbf_writer::add_string(pbf_tag_type(tag), value, size);
+    }
+
+    inline void add_string(T tag, const std::string& value) {
+        pbf_writer::add_string(pbf_tag_type(tag), value);
+    }
+
+    inline void add_string(T tag, const char* value) {
+        pbf_writer::add_string(pbf_tag_type(tag), value);
+    }
+
+    inline void add_message(T tag, const char* value, size_t size) {
+        pbf_writer::add_message(pbf_tag_type(tag), value, size);
+    }
+
+    inline void add_message(T tag, const std::string& value) {
+        pbf_writer::add_message(pbf_tag_type(tag), value);
+    }
+
+/// @cond INTERNAL
+#define PROTOZERO_WRITER_WRAP_ADD_PACKED(name) \
+    template <typename InputIterator> \
+    inline void add_packed_##name(T tag, InputIterator first, InputIterator last) { \
+        pbf_writer::add_packed_##name(pbf_tag_type(tag), first, last); \
+    }
+
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(bool)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(enum)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(int32)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(sint32)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(uint32)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(int64)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(sint64)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(uint64)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed32)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed32)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed64)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed64)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(float)
+    PROTOZERO_WRITER_WRAP_ADD_PACKED(double)
+
+#undef PROTOZERO_WRITER_WRAP_ADD_PACKED
+/// @endcond
+
+};
+
+} // end namespace protozero
+
+#endif // PROTOZERO_PBF_BUILDER_HPP
diff --git a/contrib/libosmium/protozero/pbf_message.hpp b/contrib/libosmium/protozero/pbf_message.hpp
new file mode 100644
index 0000000..7fef06f
--- /dev/null
+++ b/contrib/libosmium/protozero/pbf_message.hpp
@@ -0,0 +1,94 @@
+#ifndef PROTOZERO_PBF_MESSAGE_HPP
+#define PROTOZERO_PBF_MESSAGE_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file pbf_message.hpp
+ *
+ * @brief Contains the pbf_message class.
+ */
+
+#include <type_traits>
+
+#include <protozero/pbf_reader.hpp>
+#include <protozero/pbf_types.hpp>
+
+namespace protozero {
+
+/**
+ * This class represents a protobuf message. Either a top-level message or
+ * a nested sub-message. Top-level messages can be created from any buffer
+ * with a pointer and length:
+ *
+ * @code
+ *    enum class Message : protozero::pbf_tag_type {
+ *       ...
+ *    };
+ *
+ *    std::string buffer;
+ *    // fill buffer...
+ *    pbf_message<Message> message(buffer.data(), buffer.size());
+ * @endcode
+ *
+ * Sub-messages are created using get_message():
+ *
+ * @code
+ *    enum class SubMessage : protozero::pbf_tag_type {
+ *       ...
+ *    };
+ *
+ *    pbf_message<Message> message(...);
+ *    message.next();
+ *    pbf_message<SubMessage> submessage = message.get_message();
+ * @endcode
+ *
+ * All methods of the pbf_message class except get_bytes() and get_string()
+ * provide the strong exception guarantee, ie they either succeed or do not
+ * change the pbf_message object they are called on. Use the get_data() method
+ * instead of get_bytes() or get_string(), if you need this guarantee.
+ *
+ * This template class is based on the pbf_reader class and has all the same
+ * methods. The difference is that whereever the pbf_reader class takes an
+ * integer tag, this template class takes a tag of the template type T.
+ *
+ * Read the tutorial to understand how this class is used.
+ */
+template <typename T>
+class pbf_message : public pbf_reader {
+
+    static_assert(std::is_same<pbf_tag_type, typename std::underlying_type<T>::type>::value, "T must be enum with underlying type protozero::pbf_tag_type");
+
+public:
+
+    using enum_type = T;
+
+    template <typename... Args>
+    pbf_message(Args&&... args) noexcept :
+        pbf_reader(std::forward<Args>(args)...) {
+    }
+
+    inline bool next() {
+        return pbf_reader::next();
+    }
+
+    inline bool next(T tag) {
+        return pbf_reader::next(pbf_tag_type(tag));
+    }
+
+    inline T tag() const noexcept {
+        return T(pbf_reader::tag());
+    }
+
+};
+
+} // end namespace protozero
+
+#endif // PROTOZERO_PBF_MESSAGE_HPP
diff --git a/contrib/libosmium/protozero/pbf_reader.hpp b/contrib/libosmium/protozero/pbf_reader.hpp
new file mode 100644
index 0000000..ac3220c
--- /dev/null
+++ b/contrib/libosmium/protozero/pbf_reader.hpp
@@ -0,0 +1,1067 @@
+#ifndef PROTOZERO_PBF_READER_HPP
+#define PROTOZERO_PBF_READER_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file pbf_reader.hpp
+ *
+ * @brief Contains the pbf_reader class.
+ */
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <iterator>
+#include <string>
+#include <utility>
+
+#include <protozero/pbf_types.hpp>
+#include <protozero/exception.hpp>
+#include <protozero/varint.hpp>
+
+#if __BYTE_ORDER != __LITTLE_ENDIAN
+# include <protozero/byteswap.hpp>
+#endif
+
+/// Wrapper for assert() used for testing
+#ifndef protozero_assert
+# define protozero_assert(x) assert(x)
+#endif
+
+namespace protozero {
+
+/**
+ * This class represents a protobuf message. Either a top-level message or
+ * a nested sub-message. Top-level messages can be created from any buffer
+ * with a pointer and length:
+ *
+ * @code
+ *    std::string buffer;
+ *    // fill buffer...
+ *    pbf_reader message(buffer.data(), buffer.size());
+ * @endcode
+ *
+ * Sub-messages are created using get_message():
+ *
+ * @code
+ *    pbf_reader message(...);
+ *    message.next();
+ *    pbf_reader submessage = message.get_message();
+ * @endcode
+ *
+ * All methods of the pbf_reader class except get_bytes() and get_string()
+ * provide the strong exception guarantee, ie they either succeed or do not
+ * change the pbf_reader object they are called on. Use the get_data() method
+ * instead of get_bytes() or get_string(), if you need this guarantee.
+ */
+class pbf_reader {
+
+    // A pointer to the next unread data.
+    const char *m_data = nullptr;
+
+    // A pointer to one past the end of data.
+    const char *m_end = nullptr;
+
+    // The wire type of the current field.
+    pbf_wire_type m_wire_type = pbf_wire_type::unknown;
+
+    // The tag of the current field.
+    pbf_tag_type m_tag = 0;
+
+    template <typename T>
+    inline T get_fixed() {
+        T result;
+        skip_bytes(sizeof(T));
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+        memcpy(&result, m_data - sizeof(T), sizeof(T));
+#else
+        byteswap<sizeof(T)>(m_data - sizeof(T), reinterpret_cast<char*>(&result));
+#endif
+        return result;
+    }
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    template <typename T>
+    inline std::pair<const T*, const T*> packed_fixed() {
+        protozero_assert(tag() != 0 && "call next() before accessing field value");
+        auto len = get_len_and_skip();
+        protozero_assert(len % sizeof(T) == 0);
+        return std::make_pair(reinterpret_cast<const T*>(m_data-len), reinterpret_cast<const T*>(m_data));
+    }
+
+#else
+
+    template <typename T>
+    class const_fixed_iterator : public std::iterator<std::forward_iterator_tag, T> {
+
+        const char* m_data;
+        const char* m_end;
+
+    public:
+
+        const_fixed_iterator() noexcept :
+            m_data(nullptr),
+            m_end(nullptr) {
+        }
+
+        const_fixed_iterator(const char *data, const char* end) noexcept :
+            m_data(data),
+            m_end(end) {
+        }
+
+        const_fixed_iterator(const const_fixed_iterator&) noexcept = default;
+        const_fixed_iterator(const_fixed_iterator&&) noexcept = default;
+
+        const_fixed_iterator& operator=(const const_fixed_iterator&) noexcept = default;
+        const_fixed_iterator& operator=(const_fixed_iterator&&) noexcept = default;
+
+        ~const_fixed_iterator() noexcept = default;
+
+        T operator*() {
+            T result;
+            byteswap<sizeof(T)>(m_data, reinterpret_cast<char*>(&result));
+            return result;
+        }
+
+        const_fixed_iterator& operator++() {
+            m_data += sizeof(T);
+            return *this;
+        }
+
+        const_fixed_iterator operator++(int) {
+            const const_fixed_iterator tmp(*this);
+            ++(*this);
+            return tmp;
+        }
+
+        bool operator==(const const_fixed_iterator& rhs) const noexcept {
+            return m_data == rhs.m_data && m_end == rhs.m_end;
+        }
+
+        bool operator!=(const const_fixed_iterator& rhs) const noexcept {
+            return !(*this == rhs);
+        }
+
+    }; // class const_fixed_iterator
+
+    template <typename T>
+    inline std::pair<const_fixed_iterator<T>, const_fixed_iterator<T>> packed_fixed() {
+        protozero_assert(tag() != 0 && "call next() before accessing field value");
+        auto len = get_len_and_skip();
+        protozero_assert(len % sizeof(T) == 0);
+        return std::make_pair(const_fixed_iterator<T>(m_data-len, m_data),
+                              const_fixed_iterator<T>(m_data, m_data));
+    }
+#endif
+
+    template <typename T> inline T get_varint();
+    template <typename T> inline T get_svarint();
+
+    inline pbf_length_type get_length() { return get_varint<pbf_length_type>(); }
+
+    inline void skip_bytes(pbf_length_type len);
+
+    inline pbf_length_type get_len_and_skip();
+
+public:
+
+    /**
+     * Construct a pbf_reader message from a data pointer and a length. The pointer
+     * will be stored inside the pbf_reader object, no data is copied. So you must
+     * make sure the buffer stays valid as long as the pbf_reader object is used.
+     *
+     * The buffer must contain a complete protobuf message.
+     *
+     * @post There is no current field.
+     */
+    inline pbf_reader(const char *data, size_t length) noexcept;
+
+    /**
+     * Construct a pbf_reader message from a data pointer and a length. The pointer
+     * will be stored inside the pbf_reader object, no data is copied. So you must
+     * make sure the buffer stays valid as long as the pbf_reader object is used.
+     *
+     * The buffer must contain a complete protobuf message.
+     *
+     * @post There is no current field.
+     */
+    inline pbf_reader(std::pair<const char *, size_t> data) noexcept;
+
+    /**
+     * Construct a pbf_reader message from a std::string. A pointer to the string
+     * internals will be stored inside the pbf_reader object, no data is copied.
+     * So you must make sure the string is unchanged as long as the pbf_reader
+     * object is used.
+     *
+     * The string must contain a complete protobuf message.
+     *
+     * @post There is no current field.
+     */
+    inline pbf_reader(const std::string& data) noexcept;
+
+    /**
+     * pbf_reader can be default constructed and behaves like it has an empty
+     * buffer.
+     */
+    inline pbf_reader() noexcept = default;
+
+    /// pbf_reader messages can be copied trivially.
+    inline pbf_reader(const pbf_reader&) noexcept = default;
+
+    /// pbf_reader messages can be moved trivially.
+    inline pbf_reader(pbf_reader&&) noexcept = default;
+
+    /// pbf_reader messages can be copied trivially.
+    inline pbf_reader& operator=(const pbf_reader& other) noexcept = default;
+
+    /// pbf_reader messages can be moved trivially.
+    inline pbf_reader& operator=(pbf_reader&& other) noexcept = default;
+
+    inline ~pbf_reader() = default;
+
+    /**
+     * In a boolean context the pbf_reader class evaluates to `true` if there are
+     * still fields available and to `false` if the last field has been read.
+     */
+    inline operator bool() const noexcept;
+
+    /**
+     * Return the length in bytes of the current message. If you have
+     * already called next() and/or any of the get_*() functions, this will
+     * return the remaining length.
+     *
+     * This can, for instance, be used to estimate the space needed for a
+     * buffer. Of course you have to know reasonably well what data to expect
+     * and how it is encoded for this number to have any meaning.
+     */
+    size_t length() const noexcept {
+        return size_t(m_end - m_data);
+    }
+
+    /**
+     * Set next field in the message as the current field. This is usually
+     * called in a while loop:
+     *
+     * @code
+     *    pbf_reader message(...);
+     *    while (message.next()) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * @returns `true` if there is a next field, `false` if not.
+     * @pre There must be no current field.
+     * @post If it returns `true` there is a current field now.
+     */
+    inline bool next();
+
+    /**
+     * Set next field with given tag in the message as the current field.
+     * Fields with other tags are skipped. This is usually called in a while
+     * loop for repeated fields:
+     *
+     * @code
+     *    pbf_reader message(...);
+     *    while (message.next(17)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * or you can call it just once to get the one field with this tag:
+     *
+     * @code
+     *    pbf_reader message(...);
+     *    if (message.next(17)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * @returns `true` if there is a next field with this tag.
+     * @pre There must be no current field.
+     * @post If it returns `true` there is a current field now with the given tag.
+     */
+    inline bool next(pbf_tag_type tag);
+
+    /**
+     * The tag of the current field. The tag is the field number from the
+     * description in the .proto file.
+     *
+     * Call next() before calling this function to set the current field.
+     *
+     * @returns tag of the current field.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     */
+    inline pbf_tag_type tag() const noexcept;
+
+    /**
+     * Get the wire type of the current field. The wire types are:
+     *
+     * * 0 - varint
+     * * 1 - 64 bit
+     * * 2 - length-delimited
+     * * 5 - 32 bit
+     *
+     * All other types are illegal.
+     *
+     * Call next() before calling this function to set the current field.
+     *
+     * @returns wire type of the current field.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     */
+    inline pbf_wire_type wire_type() const noexcept;
+
+    /**
+     * Check the wire type of the current field.
+     *
+     * @returns `true` if the current field has the given wire type.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     */
+    inline bool has_wire_type(pbf_wire_type type) const noexcept;
+
+    /**
+     * Consume the current field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline void skip();
+
+    ///@{
+    /**
+     * @name Scalar field accessor functions
+     */
+
+    /**
+     * Consume and return value of current "bool" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "bool".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline bool get_bool();
+
+    /**
+     * Consume and return value of current "enum" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "enum".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline int32_t get_enum() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_varint<int32_t>();
+    }
+
+    /**
+     * Consume and return value of current "int32" varint field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "int32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline int32_t get_int32() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_varint<int32_t>();
+    }
+
+    /**
+     * Consume and return value of current "sint32" varint field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "sint32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline int32_t get_sint32() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_svarint<int32_t>();
+    }
+
+    /**
+     * Consume and return value of current "uint32" varint field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "uint32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline uint32_t get_uint32() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_varint<uint32_t>();
+    }
+
+    /**
+     * Consume and return value of current "int64" varint field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "int64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline int64_t get_int64() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_varint<int64_t>();
+    }
+
+    /**
+     * Consume and return value of current "sint64" varint field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "sint64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline int64_t get_sint64() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_svarint<int64_t>();
+    }
+
+    /**
+     * Consume and return value of current "uint64" varint field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "uint64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline uint64_t get_uint64() {
+        protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+        return get_varint<uint64_t>();
+    }
+
+    /**
+     * Consume and return value of current "fixed32" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "fixed32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline uint32_t get_fixed32();
+
+    /**
+     * Consume and return value of current "sfixed32" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "sfixed32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline int32_t get_sfixed32();
+
+    /**
+     * Consume and return value of current "fixed64" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "fixed64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline uint64_t get_fixed64();
+
+    /**
+     * Consume and return value of current "sfixed64" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "sfixed64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline int64_t get_sfixed64();
+
+    /**
+     * Consume and return value of current "float" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "float".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline float get_float();
+
+    /**
+     * Consume and return value of current "double" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "double".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline double get_double();
+
+    /**
+     * Consume and return value of current "bytes" or "string" field.
+     *
+     * @returns A pair with a pointer to the data and the length of the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "bytes" or "string".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline std::pair<const char*, pbf_length_type> get_data();
+
+    /**
+     * Consume and return value of current "bytes" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "bytes".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline std::string get_bytes();
+
+    /**
+     * Consume and return value of current "string" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "string".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline std::string get_string();
+
+    /**
+     * Consume and return value of current "message" field.
+     *
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "message".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline pbf_reader get_message() {
+        return pbf_reader(get_data());
+    }
+
+    ///@}
+
+private:
+
+    template <typename T>
+    class const_varint_iterator : public std::iterator<std::forward_iterator_tag, T> {
+
+    protected:
+
+        const char* m_data;
+        const char* m_end;
+
+    public:
+
+        const_varint_iterator() noexcept :
+            m_data(nullptr),
+            m_end(nullptr) {
+        }
+
+        const_varint_iterator(const char *data, const char* end) noexcept :
+            m_data(data),
+            m_end(end) {
+        }
+
+        const_varint_iterator(const const_varint_iterator&) noexcept = default;
+        const_varint_iterator(const_varint_iterator&&) noexcept = default;
+
+        const_varint_iterator& operator=(const const_varint_iterator&) noexcept = default;
+        const_varint_iterator& operator=(const_varint_iterator&&) noexcept = default;
+
+        ~const_varint_iterator() noexcept = default;
+
+        T operator*() {
+            const char* d = m_data; // will be thrown away
+            return static_cast<T>(decode_varint(&d, m_end));
+        }
+
+        const_varint_iterator& operator++() {
+            // Ignore the result, we call decode_varint() just for the
+            // side-effect of updating m_data.
+            decode_varint(&m_data, m_end);
+            return *this;
+        }
+
+        const_varint_iterator operator++(int) {
+            const const_varint_iterator tmp(*this);
+            ++(*this);
+            return tmp;
+        }
+
+        bool operator==(const const_varint_iterator& rhs) const noexcept {
+            return m_data == rhs.m_data && m_end == rhs.m_end;
+        }
+
+        bool operator!=(const const_varint_iterator& rhs) const noexcept {
+            return !(*this == rhs);
+        }
+
+    }; // class const_varint_iterator
+
+    template <typename T>
+    class const_svarint_iterator : public const_varint_iterator<T> {
+
+    public:
+
+        const_svarint_iterator() noexcept :
+            const_varint_iterator<T>() {
+        }
+
+        const_svarint_iterator(const char *data, const char* end) noexcept :
+            const_varint_iterator<T>(data, end) {
+        }
+
+        const_svarint_iterator(const const_svarint_iterator&) = default;
+        const_svarint_iterator(const_svarint_iterator&&) = default;
+
+        const_svarint_iterator& operator=(const const_svarint_iterator&) = default;
+        const_svarint_iterator& operator=(const_svarint_iterator&&) = default;
+
+        ~const_svarint_iterator() = default;
+
+        T operator*() {
+            const char* d = this->m_data; // will be thrown away
+            return static_cast<T>(decode_zigzag64(decode_varint(&d, this->m_end)));
+        }
+
+        const_svarint_iterator& operator++() {
+            // Ignore the result, we call decode_varint() just for the
+            // side-effect of updating m_data.
+            decode_varint(&this->m_data, this->m_end);
+            return *this;
+        }
+
+        const_svarint_iterator operator++(int) {
+            const const_svarint_iterator tmp(*this);
+            ++(*this);
+            return tmp;
+        }
+
+    }; // class const_svarint_iterator
+
+public:
+
+    /// Forward iterator for iterating over bool (int32 varint) values.
+    typedef const_varint_iterator< int32_t> const_bool_iterator;
+
+    /// Forward iterator for iterating over enum (int32 varint) values.
+    typedef const_varint_iterator< int32_t> const_enum_iterator;
+
+    /// Forward iterator for iterating over int32 (varint) values.
+    typedef const_varint_iterator< int32_t> const_int32_iterator;
+
+    /// Forward iterator for iterating over sint32 (varint) values.
+    typedef const_svarint_iterator<int32_t> const_sint32_iterator;
+
+    /// Forward iterator for iterating over uint32 (varint) values.
+    typedef const_varint_iterator<uint32_t> const_uint32_iterator;
+
+    /// Forward iterator for iterating over int64 (varint) values.
+    typedef const_varint_iterator< int64_t> const_int64_iterator;
+
+    /// Forward iterator for iterating over sint64 (varint) values.
+    typedef const_svarint_iterator<int64_t> const_sint64_iterator;
+
+    /// Forward iterator for iterating over uint64 (varint) values.
+    typedef const_varint_iterator<uint64_t> const_uint64_iterator;
+
+    ///@{
+    /**
+     * @name Repeated packed field accessor functions
+     */
+
+    /**
+     * Consume current "repeated packed bool" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed bool".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline std::pair<pbf_reader::const_bool_iterator, pbf_reader::const_bool_iterator> get_packed_bool();
+
+    /**
+     * Consume current "repeated packed enum" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed enum".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline std::pair<pbf_reader::const_enum_iterator, pbf_reader::const_enum_iterator> get_packed_enum();
+
+    /**
+     * Consume current "repeated packed int32" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed int32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline std::pair<pbf_reader::const_int32_iterator, pbf_reader::const_int32_iterator> get_packed_int32();
+
+    /**
+     * Consume current "repeated packed sint32" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed sint32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline std::pair<pbf_reader::const_sint32_iterator, pbf_reader::const_sint32_iterator> get_packed_sint32();
+
+    /**
+     * Consume current "repeated packed uint32" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed uint32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline std::pair<pbf_reader::const_uint32_iterator, pbf_reader::const_uint32_iterator> get_packed_uint32();
+
+    /**
+     * Consume current "repeated packed int64" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed int64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline std::pair<pbf_reader::const_int64_iterator, pbf_reader::const_int64_iterator> get_packed_int64();
+
+    /**
+     * Consume current "repeated packed sint64" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed sint64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline std::pair<pbf_reader::const_sint64_iterator, pbf_reader::const_sint64_iterator> get_packed_sint64();
+
+    /**
+     * Consume current "repeated packed uint64" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed uint64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline std::pair<pbf_reader::const_uint64_iterator, pbf_reader::const_uint64_iterator> get_packed_uint64();
+
+    /**
+     * Consume current "repeated packed fixed32" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed fixed32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline auto get_packed_fixed32() -> decltype(packed_fixed<uint32_t>()) {
+        return packed_fixed<uint32_t>();
+    }
+
+    /**
+     * Consume current "repeated packed sfixed32" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed sfixed32".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline auto get_packed_sfixed32() -> decltype(packed_fixed<int32_t>()) {
+        return packed_fixed<int32_t>();
+    }
+
+    /**
+     * Consume current "repeated packed fixed64" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed fixed64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline auto get_packed_fixed64() -> decltype(packed_fixed<uint64_t>()) {
+        return packed_fixed<uint64_t>();
+    }
+
+    /**
+     * Consume current "repeated packed sfixed64" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed sfixed64".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline auto get_packed_sfixed64() -> decltype(packed_fixed<int64_t>()) {
+        return packed_fixed<int64_t>();
+    }
+
+    /**
+     * Consume current "repeated packed float" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed float".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline auto get_packed_float() -> decltype(packed_fixed<float>()) {
+        return packed_fixed<float>();
+    }
+
+    /**
+     * Consume current "repeated packed double" field.
+     *
+     * @returns a pair of iterators to the beginning and one past the end of
+     *          the data.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     * @pre The current field must be of type "repeated packed double".
+     * @post The current field was consumed and there is no current field now.
+     */
+    inline auto get_packed_double() -> decltype(packed_fixed<double>()) {
+        return packed_fixed<double>();
+    }
+
+    ///@}
+
+}; // class pbf_reader
+
+pbf_reader::pbf_reader(const char *data, size_t length) noexcept
+    : m_data(data),
+      m_end(data + length),
+      m_wire_type(pbf_wire_type::unknown),
+      m_tag(0) {
+}
+
+pbf_reader::pbf_reader(std::pair<const char *, size_t> data) noexcept
+    : m_data(data.first),
+      m_end(data.first + data.second),
+      m_wire_type(pbf_wire_type::unknown),
+      m_tag(0) {
+}
+
+pbf_reader::pbf_reader(const std::string& data) noexcept
+    : m_data(data.data()),
+      m_end(data.data() + data.size()),
+      m_wire_type(pbf_wire_type::unknown),
+      m_tag(0) {
+}
+
+pbf_reader::operator bool() const noexcept {
+    return m_data < m_end;
+}
+
+bool pbf_reader::next() {
+    if (m_data == m_end) {
+        return false;
+    }
+
+    auto value = get_varint<uint32_t>();
+    m_tag = value >> 3;
+
+    // tags 0 and 19000 to 19999 are not allowed as per
+    // https://developers.google.com/protocol-buffers/docs/proto
+    protozero_assert(((m_tag > 0 && m_tag < 19000) || (m_tag > 19999 && m_tag <= ((1 << 29) - 1))) && "tag out of range");
+
+    m_wire_type = pbf_wire_type(value & 0x07);
+    switch (m_wire_type) {
+        case pbf_wire_type::varint:
+        case pbf_wire_type::fixed64:
+        case pbf_wire_type::length_delimited:
+        case pbf_wire_type::fixed32:
+            break;
+        default:
+            throw unknown_pbf_wire_type_exception();
+    }
+
+    return true;
+}
+
+bool pbf_reader::next(pbf_tag_type requested_tag) {
+    while (next()) {
+        if (m_tag == requested_tag) {
+            return true;
+        } else {
+            skip();
+        }
+    }
+    return false;
+}
+
+pbf_tag_type pbf_reader::tag() const noexcept {
+    return m_tag;
+}
+
+pbf_wire_type pbf_reader::wire_type() const noexcept {
+    return m_wire_type;
+}
+
+bool pbf_reader::has_wire_type(pbf_wire_type type) const noexcept {
+    return wire_type() == type;
+}
+
+void pbf_reader::skip_bytes(pbf_length_type len) {
+    if (m_data + len > m_end) {
+        throw end_of_buffer_exception();
+    }
+    m_data += len;
+
+// In debug builds reset the tag to zero so that we can detect (some)
+// wrong code.
+#ifndef NDEBUG
+    m_tag = 0;
+#endif
+}
+
+void pbf_reader::skip() {
+    protozero_assert(tag() != 0 && "call next() before calling skip()");
+    switch (wire_type()) {
+        case pbf_wire_type::varint:
+            (void)get_uint32(); // called for the side-effect of skipping value
+            break;
+        case pbf_wire_type::fixed64:
+            skip_bytes(8);
+            break;
+        case pbf_wire_type::length_delimited:
+            skip_bytes(get_length());
+            break;
+        case pbf_wire_type::fixed32:
+            skip_bytes(4);
+            break;
+        default:
+            throw unknown_pbf_wire_type_exception();
+    }
+}
+
+pbf_length_type pbf_reader::get_len_and_skip() {
+    auto len = get_length();
+    skip_bytes(len);
+    return len;
+}
+
+template <typename T>
+T pbf_reader::get_varint() {
+    return static_cast<T>(decode_varint(&m_data, m_end));
+}
+
+template <typename T>
+T pbf_reader::get_svarint() {
+    protozero_assert((has_wire_type(pbf_wire_type::varint) || has_wire_type(pbf_wire_type::length_delimited)) && "not a varint");
+    return static_cast<T>(decode_zigzag64(decode_varint(&m_data, m_end)));
+}
+
+uint32_t pbf_reader::get_fixed32() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    protozero_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed");
+    return get_fixed<uint32_t>();
+}
+
+int32_t pbf_reader::get_sfixed32() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    protozero_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed");
+    return get_fixed<int32_t>();
+}
+
+uint64_t pbf_reader::get_fixed64() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    protozero_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed");
+    return get_fixed<uint64_t>();
+}
+
+int64_t pbf_reader::get_sfixed64() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    protozero_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed");
+    return get_fixed<int64_t>();
+}
+
+float pbf_reader::get_float() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    protozero_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed");
+    return get_fixed<float>();
+}
+
+double pbf_reader::get_double() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    protozero_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed");
+    return get_fixed<double>();
+}
+
+bool pbf_reader::get_bool() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
+    protozero_assert((*m_data & 0x80) == 0 && "not a 1 byte varint");
+    skip_bytes(1);
+    return m_data[-1] != 0; // -1 okay because we incremented m_data the line before
+}
+
+std::pair<const char*, pbf_length_type> pbf_reader::get_data() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    protozero_assert(has_wire_type(pbf_wire_type::length_delimited) && "not of type string, bytes or message");
+    auto len = get_len_and_skip();
+    return std::make_pair(m_data-len, len);
+}
+
+std::string pbf_reader::get_bytes() {
+    auto d = get_data();
+    return std::string(d.first, d.second);
+}
+
+std::string pbf_reader::get_string() {
+    return get_bytes();
+}
+
+std::pair<pbf_reader::const_bool_iterator, pbf_reader::const_bool_iterator> pbf_reader::get_packed_bool() {
+    return get_packed_int32();
+}
+
+std::pair<pbf_reader::const_enum_iterator, pbf_reader::const_enum_iterator> pbf_reader::get_packed_enum() {
+    return get_packed_int32();
+}
+
+std::pair<pbf_reader::const_int32_iterator, pbf_reader::const_int32_iterator> pbf_reader::get_packed_int32() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    auto len = get_len_and_skip();
+    return std::make_pair(pbf_reader::const_int32_iterator(m_data-len, m_data),
+                          pbf_reader::const_int32_iterator(m_data, m_data));
+}
+
+std::pair<pbf_reader::const_uint32_iterator, pbf_reader::const_uint32_iterator> pbf_reader::get_packed_uint32() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    auto len = get_len_and_skip();
+    return std::make_pair(pbf_reader::const_uint32_iterator(m_data-len, m_data),
+                          pbf_reader::const_uint32_iterator(m_data, m_data));
+}
+
+std::pair<pbf_reader::const_sint32_iterator, pbf_reader::const_sint32_iterator> pbf_reader::get_packed_sint32() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    auto len = get_len_and_skip();
+    return std::make_pair(pbf_reader::const_sint32_iterator(m_data-len, m_data),
+                          pbf_reader::const_sint32_iterator(m_data, m_data));
+}
+
+std::pair<pbf_reader::const_int64_iterator, pbf_reader::const_int64_iterator> pbf_reader::get_packed_int64() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    auto len = get_len_and_skip();
+    return std::make_pair(pbf_reader::const_int64_iterator(m_data-len, m_data),
+                          pbf_reader::const_int64_iterator(m_data, m_data));
+}
+
+std::pair<pbf_reader::const_uint64_iterator, pbf_reader::const_uint64_iterator> pbf_reader::get_packed_uint64() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    auto len = get_len_and_skip();
+    return std::make_pair(pbf_reader::const_uint64_iterator(m_data-len, m_data),
+                          pbf_reader::const_uint64_iterator(m_data, m_data));
+}
+
+std::pair<pbf_reader::const_sint64_iterator, pbf_reader::const_sint64_iterator> pbf_reader::get_packed_sint64() {
+    protozero_assert(tag() != 0 && "call next() before accessing field value");
+    auto len = get_len_and_skip();
+    return std::make_pair(pbf_reader::const_sint64_iterator(m_data-len, m_data),
+                          pbf_reader::const_sint64_iterator(m_data, m_data));
+}
+
+} // end namespace protozero
+
+#endif // PROTOZERO_PBF_READER_HPP
diff --git a/contrib/libosmium/protozero/pbf_types.hpp b/contrib/libosmium/protozero/pbf_types.hpp
new file mode 100644
index 0000000..9f38584
--- /dev/null
+++ b/contrib/libosmium/protozero/pbf_types.hpp
@@ -0,0 +1,49 @@
+#ifndef PROTOZERO_PBF_TYPES_HPP
+#define PROTOZERO_PBF_TYPES_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file pbf_types.hpp
+ *
+ * @brief Contains the declaration of low-level types used in the pbf format.
+ */
+
+#include <cstdint>
+
+namespace protozero {
+
+    /**
+     * The type used for field tags (field numbers).
+     */
+    typedef uint32_t pbf_tag_type;
+
+    /**
+     * The type used to encode type information.
+     * See the table on
+     *    https://developers.google.com/protocol-buffers/docs/encoding
+     */
+    enum class pbf_wire_type : uint32_t {
+        varint           = 0, // int32/64, uint32/64, sint32/64, bool, enum
+        fixed64          = 1, // fixed64, sfixed64, double
+        length_delimited = 2, // string, bytes, embedded messages,
+                              // packed repeated fields
+        fixed32          = 5, // fixed32, sfixed32, float
+        unknown          = 99 // used for default setting in this library
+    };
+
+    /**
+     * The type used for length values, such as the length of a field.
+     */
+    typedef uint32_t pbf_length_type;
+
+} // end namespace protozero
+
+#endif // PROTOZERO_PBF_TYPES_HPP
diff --git a/contrib/libosmium/protozero/pbf_writer.hpp b/contrib/libosmium/protozero/pbf_writer.hpp
new file mode 100644
index 0000000..e4e02de
--- /dev/null
+++ b/contrib/libosmium/protozero/pbf_writer.hpp
@@ -0,0 +1,666 @@
+#ifndef PROTOZERO_PBF_WRITER_HPP
+#define PROTOZERO_PBF_WRITER_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file pbf_writer.hpp
+ *
+ * @brief Contains the pbf_writer class.
+ */
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <string>
+
+#include <protozero/pbf_types.hpp>
+#include <protozero/varint.hpp>
+
+#if __BYTE_ORDER != __LITTLE_ENDIAN
+# include <protozero/byteswap.hpp>
+#endif
+
+/// Wrapper for assert() used for testing
+#ifndef protozero_assert
+# define protozero_assert(x) assert(x)
+#endif
+
+namespace protozero {
+
+/**
+ * The pbf_writer is used to write PBF formatted messages into a buffer.
+ *
+ * Almost all methods in this class can throw an std::bad_alloc exception if
+ * the std::string used as a buffer wants to resize.
+ */
+class pbf_writer {
+
+    std::string* m_data;
+    pbf_writer* m_parent_writer;
+    size_t m_pos = 0;
+
+    inline void add_varint(uint64_t value) {
+        protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
+        protozero_assert(m_data);
+        write_varint(std::back_inserter(*m_data), value);
+    }
+
+    inline void add_field(pbf_tag_type tag, pbf_wire_type type) {
+        protozero_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1 << 29) - 1))) && "tag out of range");
+        uint32_t b = (tag << 3) | uint32_t(type);
+        add_varint(b);
+    }
+
+    inline void add_tagged_varint(pbf_tag_type tag, uint64_t value) {
+        add_field(tag, pbf_wire_type::varint);
+        add_varint(value);
+    }
+
+    template <typename T>
+    inline void add_fixed(T value) {
+        protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
+        protozero_assert(m_data);
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+        m_data->append(reinterpret_cast<const char*>(&value), sizeof(T));
+#else
+        auto size = m_data->size();
+        m_data->resize(size + sizeof(T));
+        byteswap<sizeof(T)>(reinterpret_cast<const char*>(&value), const_cast<char*>(m_data->data() + size));
+#endif
+    }
+
+    template <typename T, typename It>
+    inline void add_packed_fixed(pbf_tag_type tag, It first, It last, std::input_iterator_tag) {
+        if (first == last) {
+            return;
+        }
+
+        pbf_writer sw(*this, tag);
+
+        while (first != last) {
+            sw.add_fixed<T>(*first++);
+        }
+    }
+
+    template <typename T, typename It>
+    inline void add_packed_fixed(pbf_tag_type tag, It first, It last, std::forward_iterator_tag) {
+        if (first == last) {
+            return;
+        }
+
+        add_length_varint(tag, sizeof(T) * pbf_length_type(std::distance(first, last)));
+
+        while (first != last) {
+            add_fixed<T>(*first++);
+        }
+    }
+
+    template <typename It>
+    inline void add_packed_varint(pbf_tag_type tag, It first, It last) {
+        if (first == last) {
+            return;
+        }
+
+        pbf_writer sw(*this, tag);
+
+        while (first != last) {
+            sw.add_varint(uint64_t(*first++));
+        }
+    }
+
+    template <typename It>
+    inline void add_packed_svarint(pbf_tag_type tag, It first, It last) {
+        if (first == last) {
+            return;
+        }
+
+        pbf_writer sw(*this, tag);
+
+        while (first != last) {
+            sw.add_varint(encode_zigzag64(*first++));
+        }
+    }
+
+    // The number of bytes to reserve for the varint holding the length of
+    // a length-delimited field. The length has to fit into pbf_length_type,
+    // and a varint needs 8 bit for every 7 bit.
+    static const int reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1;
+
+    inline void open_submessage(pbf_tag_type tag) {
+        protozero_assert(m_pos == 0);
+        protozero_assert(m_data);
+        add_field(tag, pbf_wire_type::length_delimited);
+        m_data->append(size_t(reserve_bytes), '\0');
+        m_pos = m_data->size();
+    }
+
+    inline void close_submessage() {
+        protozero_assert(m_pos != 0);
+        protozero_assert(m_data);
+        auto length = pbf_length_type(m_data->size() - m_pos);
+
+        protozero_assert(m_data->size() >= m_pos - reserve_bytes);
+        auto n = write_varint(m_data->begin() + long(m_pos) - reserve_bytes, length);
+
+        m_data->erase(m_data->begin() + long(m_pos) - reserve_bytes + n, m_data->begin() + long(m_pos));
+        m_pos = 0;
+    }
+
+    inline void add_length_varint(pbf_tag_type tag, pbf_length_type length) {
+        add_field(tag, pbf_wire_type::length_delimited);
+        add_varint(length);
+    }
+
+public:
+
+    /**
+     * Create a writer using the given string as a data store. The pbf_writer
+     * stores a reference to that string and adds all data to it.
+     */
+    inline explicit pbf_writer(std::string& data) noexcept :
+        m_data(&data),
+        m_parent_writer(nullptr),
+        m_pos(0) {
+    }
+
+    /**
+     * Create a writer without a data store. In this form the writer can not
+     * be used!
+     */
+    inline pbf_writer() noexcept :
+        m_data(nullptr),
+        m_parent_writer(nullptr),
+        m_pos(0) {
+    }
+
+    /**
+     * Construct a pbf_writer for a submessage from the pbf_writer of the
+     * parent message.
+     *
+     * @param parent_writer The pbf_writer
+     * @param tag Tag (field number) of the field that will be written
+     */
+    inline pbf_writer(pbf_writer& parent_writer, pbf_tag_type tag) :
+        m_data(parent_writer.m_data),
+        m_parent_writer(&parent_writer),
+        m_pos(0) {
+        m_parent_writer->open_submessage(tag);
+    }
+
+    /// A pbf_writer object can be copied
+    pbf_writer(const pbf_writer&) noexcept = default;
+
+    /// A pbf_writer object can be copied
+    pbf_writer& operator=(const pbf_writer&) noexcept = default;
+
+    /// A pbf_writer object can be moved
+    inline pbf_writer(pbf_writer&&) noexcept = default;
+
+    /// A pbf_writer object can be moved
+    inline pbf_writer& operator=(pbf_writer&&) noexcept = default;
+
+    inline ~pbf_writer() {
+        if (m_parent_writer) {
+            m_parent_writer->close_submessage();
+        }
+    }
+
+    ///@{
+    /**
+     * @name Scalar field writer functions
+     */
+
+    /**
+     * Add "bool" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_bool(pbf_tag_type tag, bool value) {
+        add_field(tag, pbf_wire_type::varint);
+        protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
+        protozero_assert(m_data);
+        m_data->append(1, value);
+    }
+
+    /**
+     * Add "enum" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_enum(pbf_tag_type tag, int32_t value) {
+        add_tagged_varint(tag, uint64_t(value));
+    }
+
+    /**
+     * Add "int32" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_int32(pbf_tag_type tag, int32_t value) {
+        add_tagged_varint(tag, uint64_t(value));
+    }
+
+    /**
+     * Add "sint32" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_sint32(pbf_tag_type tag, int32_t value) {
+        add_tagged_varint(tag, encode_zigzag32(value));
+    }
+
+    /**
+     * Add "uint32" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_uint32(pbf_tag_type tag, uint32_t value) {
+        add_tagged_varint(tag, value);
+    }
+
+    /**
+     * Add "int64" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_int64(pbf_tag_type tag, int64_t value) {
+        add_tagged_varint(tag, uint64_t(value));
+    }
+
+    /**
+     * Add "sint64" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_sint64(pbf_tag_type tag, int64_t value) {
+        add_tagged_varint(tag, encode_zigzag64(value));
+    }
+
+    /**
+     * Add "uint64" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_uint64(pbf_tag_type tag, uint64_t value) {
+        add_tagged_varint(tag, value);
+    }
+
+    /**
+     * Add "fixed32" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_fixed32(pbf_tag_type tag, uint32_t value) {
+        add_field(tag, pbf_wire_type::fixed32);
+        add_fixed<uint32_t>(value);
+    }
+
+    /**
+     * Add "sfixed32" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_sfixed32(pbf_tag_type tag, int32_t value) {
+        add_field(tag, pbf_wire_type::fixed32);
+        add_fixed<int32_t>(value);
+    }
+
+    /**
+     * Add "fixed64" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_fixed64(pbf_tag_type tag, uint64_t value) {
+        add_field(tag, pbf_wire_type::fixed64);
+        add_fixed<uint64_t>(value);
+    }
+
+    /**
+     * Add "sfixed64" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_sfixed64(pbf_tag_type tag, int64_t value) {
+        add_field(tag, pbf_wire_type::fixed64);
+        add_fixed<int64_t>(value);
+    }
+
+    /**
+     * Add "float" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_float(pbf_tag_type tag, float value) {
+        add_field(tag, pbf_wire_type::fixed32);
+        add_fixed<float>(value);
+    }
+
+    /**
+     * Add "double" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_double(pbf_tag_type tag, double value) {
+        add_field(tag, pbf_wire_type::fixed64);
+        add_fixed<double>(value);
+    }
+
+    /**
+     * Add "bytes" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Pointer to value to be written
+     * @param size Number of bytes to be written
+     */
+    inline void add_bytes(pbf_tag_type tag, const char* value, size_t size) {
+        protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
+        protozero_assert(m_data);
+        assert(size <= std::numeric_limits<pbf_length_type>::max());
+        add_length_varint(tag, pbf_length_type(size));
+        m_data->append(value, size);
+    }
+
+    /**
+     * Add "bytes" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_bytes(pbf_tag_type tag, const std::string& value) {
+        add_bytes(tag, value.data(), value.size());
+    }
+
+    /**
+     * Add "string" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Pointer to value to be written
+     * @param size Number of bytes to be written
+     */
+    inline void add_string(pbf_tag_type tag, const char* value, size_t size) {
+        add_bytes(tag, value, size);
+    }
+
+    /**
+     * Add "string" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written
+     */
+    inline void add_string(pbf_tag_type tag, const std::string& value) {
+        add_bytes(tag, value.data(), value.size());
+    }
+
+    /**
+     * Add "string" field to data. Bytes from the value are written until
+     * a null byte is encountered. The null byte is not added.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Pointer to value to be written
+     */
+    inline void add_string(pbf_tag_type tag, const char* value) {
+        add_bytes(tag, value, std::strlen(value));
+    }
+
+    /**
+     * Add "message" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Pointer to message to be written
+     * @param size Length of the message
+     */
+    inline void add_message(pbf_tag_type tag, const char* value, size_t size) {
+        add_bytes(tag, value, size);
+    }
+
+    /**
+     * Add "message" field to data.
+     *
+     * @param tag Tag (field number) of the field
+     * @param value Value to be written. The value must be a complete message.
+     */
+    inline void add_message(pbf_tag_type tag, const std::string& value) {
+        add_bytes(tag, value.data(), value.size());
+    }
+
+    ///@}
+
+    ///@{
+    /**
+     * @name Repeated packed field writer functions
+     */
+
+    /**
+     * Add "repeated packed bool" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to bool.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_varint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed enum" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int32_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_varint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed int32" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int32_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_varint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed sint32" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int32_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_svarint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed uint32" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to uint32_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_varint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed int64" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int64_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_varint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed sint64" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int64_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_svarint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed uint64" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to uint64_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_varint(tag, first, last);
+    }
+
+    /**
+     * Add "repeated packed fixed32" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to uint32_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_fixed<uint32_t, InputIterator>(tag, first, last,
+            typename std::iterator_traits<InputIterator>::iterator_category());
+    }
+
+    /**
+     * Add "repeated packed sfixed32" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int32_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_fixed<int32_t, InputIterator>(tag, first, last,
+            typename std::iterator_traits<InputIterator>::iterator_category());
+    }
+
+    /**
+     * Add "repeated packed fixed64" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to uint64_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_fixed<uint64_t, InputIterator>(tag, first, last,
+            typename std::iterator_traits<InputIterator>::iterator_category());
+    }
+
+    /**
+     * Add "repeated packed sfixed64" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to int64_t.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_fixed<int64_t, InputIterator>(tag, first, last,
+            typename std::iterator_traits<InputIterator>::iterator_category());
+    }
+
+    /**
+     * Add "repeated packed float" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to float.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_fixed<float, InputIterator>(tag, first, last,
+            typename std::iterator_traits<InputIterator>::iterator_category());
+    }
+
+    /**
+     * Add "repeated packed double" field to data.
+     *
+     * @tparam InputIterator An type satisfying the InputIterator concept.
+     *         Dereferencing the iterator must yield a type assignable to double.
+     * @param tag Tag (field number) of the field
+     * @param first Iterator pointing to the beginning of the data
+     * @param last Iterator pointing one past the end of data
+     */
+    template <typename InputIterator>
+    inline void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last) {
+        add_packed_fixed<double, InputIterator>(tag, first, last,
+            typename std::iterator_traits<InputIterator>::iterator_category());
+    }
+
+    ///@}
+
+}; // class pbf_writer
+
+} // end namespace protozero
+
+#endif // PROTOZERO_PBF_WRITER_HPP
diff --git a/contrib/libosmium/protozero/varint.hpp b/contrib/libosmium/protozero/varint.hpp
new file mode 100644
index 0000000..27536fd
--- /dev/null
+++ b/contrib/libosmium/protozero/varint.hpp
@@ -0,0 +1,132 @@
+#ifndef PROTOZERO_VARINT_HPP
+#define PROTOZERO_VARINT_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+/**
+ * @file varint.hpp
+ *
+ * @brief Contains low-level varint and zigzag encoding and decoding functions.
+ */
+
+#include <cstdint>
+
+#include <protozero/exception.hpp>
+
+namespace protozero {
+
+/**
+ * The maximum length of a 64bit varint.
+ */
+const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1;
+
+// from https://github.com/facebook/folly/blob/master/folly/Varint.h
+/**
+ * Decode a 64bit varint.
+ *
+ * String exception guarantee: if there is an exception the data pointer will
+ * not be changed.
+ *
+ * @param[in,out] data Pointer to pointer to the input data. After the function
+ *        returns this will point to the next data to be read.
+ * @param[in] end Pointer one past the end of the input data.
+ * @returns The decoded integer
+ * @throws varint_too_long_exception if the varint is longer then the maximum
+ *         length that would fit in a 64bit int. Usually this means your data
+ *         is corrupted or you are trying to read something as a varint that
+ *         isn't.
+ * @throws end_of_buffer_exception if the *end* of the buffer was reached
+ *         before the end of the varint.
+ */
+inline uint64_t decode_varint(const char** data, const char* end) {
+    const int8_t* begin = reinterpret_cast<const int8_t*>(*data);
+    const int8_t* iend = reinterpret_cast<const int8_t*>(end);
+    const int8_t* p = begin;
+    uint64_t val = 0;
+
+    if (iend - begin >= max_varint_length) {  // fast path
+        do {
+            int64_t b;
+            b = *p++; val  = uint64_t((b & 0x7f)      ); if (b >= 0) break;
+            b = *p++; val |= uint64_t((b & 0x7f) <<  7); if (b >= 0) break;
+            b = *p++; val |= uint64_t((b & 0x7f) << 14); if (b >= 0) break;
+            b = *p++; val |= uint64_t((b & 0x7f) << 21); if (b >= 0) break;
+            b = *p++; val |= uint64_t((b & 0x7f) << 28); if (b >= 0) break;
+            b = *p++; val |= uint64_t((b & 0x7f) << 35); if (b >= 0) break;
+            b = *p++; val |= uint64_t((b & 0x7f) << 42); if (b >= 0) break;
+            b = *p++; val |= uint64_t((b & 0x7f) << 49); if (b >= 0) break;
+            b = *p++; val |= uint64_t((b & 0x7f) << 56); if (b >= 0) break;
+            b = *p++; val |= uint64_t((b & 0x7f) << 63); if (b >= 0) break;
+            throw varint_too_long_exception();
+        } while (false);
+    } else {
+        int shift = 0;
+        while (p != iend && *p < 0) {
+            val |= uint64_t(*p++ & 0x7f) << shift;
+            shift += 7;
+        }
+        if (p == iend) {
+            throw end_of_buffer_exception();
+        }
+        val |= uint64_t(*p++) << shift;
+    }
+
+    *data = reinterpret_cast<const char*>(p);
+    return val;
+}
+
+/**
+ * Varint-encode a 64bit integer.
+ */
+template <typename OutputIterator>
+inline int write_varint(OutputIterator data, uint64_t value) {
+    int n=1;
+
+    while (value >= 0x80) {
+        *data++ = char((value & 0x7f) | 0x80);
+        value >>= 7;
+        ++n;
+    }
+    *data++ = char(value);
+
+    return n;
+}
+
+/**
+ * ZigZag encodes a 32 bit integer.
+ */
+inline uint32_t encode_zigzag32(int32_t value) noexcept {
+    return (static_cast<uint32_t>(value) << 1) ^ (static_cast<uint32_t>(value >> 31));
+}
+
+/**
+ * ZigZag encodes a 64 bit integer.
+ */
+inline uint64_t encode_zigzag64(int64_t value) noexcept {
+    return (static_cast<uint64_t>(value) << 1) ^ (static_cast<uint64_t>(value >> 63));
+}
+
+/**
+ * Decodes a 32 bit ZigZag-encoded integer.
+ */
+inline int32_t decode_zigzag32(uint32_t value) noexcept {
+    return int32_t(value >> 1) ^ -int32_t(value & 1);
+}
+
+/**
+ * Decodes a 64 bit ZigZag-encoded integer.
+ */
+inline int64_t decode_zigzag64(uint64_t value) noexcept {
+    return int64_t(value >> 1) ^ -int64_t(value & 1);
+}
+
+} // end namespace protozero
+
+#endif // PROTOZERO_VARINT_HPP
diff --git a/contrib/libosmium/protozero/version.hpp b/contrib/libosmium/protozero/version.hpp
new file mode 100644
index 0000000..f11d303
--- /dev/null
+++ b/contrib/libosmium/protozero/version.hpp
@@ -0,0 +1,22 @@
+#ifndef PROTOZERO_VERSION_HPP
+#define PROTOZERO_VERSION_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+#define PROTOZERO_VERSION_MAJOR 1
+#define PROTOZERO_VERSION_MINOR 2
+#define PROTOZERO_VERSION_PATCH 2
+
+#define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH)
+
+#define PROTOZERO_VERSION_STRING "1.2.2"
+
+
+#endif // PROTOZERO_VERSION_HPP
diff --git a/default.style b/default.style
index 30cd48c..217b4a2 100644
--- a/default.style
+++ b/default.style
@@ -16,7 +16,7 @@
 #
 # Flags: Flags that indicate what table the OSM object is moved into.
 #
-# There are 5 possible flags. These flags are used both to indicate if a column
+# There are 6 possible flags. These flags are used both to indicate if a column
 # should be created, and if ways with the tag are assumed to be areas. The area
 # assumptions can be overridden with an area=yes/no tag
 #
@@ -24,7 +24,10 @@
 #
 # linear - Create a column for this tag
 #
-# phstore - Don't create a column for this tag, but objects with the tag are areas
+# nocolumn - Override the above and don't create a column for the tag, but do
+# include objects with this tag
+#
+# phstore - Same as polygon,nocolumn for backward compatibility
 #
 # delete - Drop this tag completely and don't create a column for it. This also
 # prevents the tag from being added to hstore columns
@@ -152,12 +155,12 @@ way        way_area     real         linear # This is calculated during import
 # Area tags
 # We don't make columns for these tags, but objects with them are areas.
 # Mainly for use with hstore
-way         abandoned:aeroway       text    phstore
-way         abandoned:amenity       text    phstore
-way         abandoned:building      text    phstore
-way         abandoned:landuse       text    phstore
-way         abandoned:power         text    phstore
-way         area:highway            text    phstore
+way         abandoned:aeroway       text    polygon,nocolumn
+way         abandoned:amenity       text    polygon,nocolumn
+way         abandoned:building      text    polygon,nocolumn
+way         abandoned:landuse       text    polygon,nocolumn
+way         abandoned:power         text    polygon,nocolumn
+way         area:highway            text    polygon,nocolumn
 
 # Deleted tags
 # These are tags that are generally regarded as useless for most rendering.
diff --git a/docs/Doxyfile b/docs/Doxyfile
new file mode 100644
index 0000000..a0af86a
--- /dev/null
+++ b/docs/Doxyfile
@@ -0,0 +1,2362 @@
+# Doxyfile 1.8.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "osm2pgsql"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "OpenStreetMap data to PostgreSQL converter"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = "docs"
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          = *.c *.cpp *.h *.hpp *.md
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  = *.h *.hpp
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/docs/lua.md b/docs/lua.md
index c88f64c..6ebf9da 100644
--- a/docs/lua.md
+++ b/docs/lua.md
@@ -29,9 +29,9 @@ The second return value is `tags`, a transformed (or unchanged) set of tags.
 
 `filter_tags_way` returns two additional flags. `poly` should be `1` if the way should be treated as a polygon, `0` as a line. `roads` should be `1` if the way should be added to the planet_osm_roads table, `0` otherwise.
 
-    function filter_tags_relation_member(tags, member_tags, 
+    function filter_tags_relation_member(tags, member_tags,
         roles, num_members)
-    return filter, tags, member_superseded, boundary, 
+    return filter, tags, member_superseded, boundary,
         polygon, roads
 
 The function filter_tags_relation_member is more complex and can handle more advanced relation tagging, such as multipolygons that take their tags from the member ways.
diff --git a/docs/multi.md b/docs/multi.md
index 887319f..a35304b 100644
--- a/docs/multi.md
+++ b/docs/multi.md
@@ -5,7 +5,7 @@ to the standard [pgsql](pgsql.md) backend tables. It is intended to allow
 the configuration of a custom set of tables with hopefully fewer rows and fewer
 columns. This can be beneficial to queries in which some context (eg. zoom level)
 could limit the number of tables that need to be queried. Addtionaly it would
-allow more tables to be queried in parallel. 
+allow more tables to be queried in parallel.
 
 ## Database Layout ##
 It connects to a PostgreSQL database and stores the data in one or more tables.
@@ -16,39 +16,53 @@ That is essentially why it was named `multi` because it's basically multiple
 ## Table Configuration ##
 As sample configuration may resemble the following:
 
-    [
-      {
-        "name": "building",
-        "type": "polygon",
-        "tagtransform": "building.lua",
-        "tagtransform-node-function": "nodes_proc",
-        "tagtransform-way-function": "ways_proc",
-        "tagtransform-relation-function": "rels_proc",
-        "tagtransform-relation-member-function": "rel_members_proc",
-        "tags": [
-          {"name": "building", "type": "text"},
-          {"name": "shop", "type": "text"},
-          {"name": "amenity", "type": "text"}
-        ]
-      },
-      ...
+```json
+[
+  {
+    "name": "building",
+    "type": "polygon",
+    "tagtransform": "building.lua",
+    "tagtransform-node-function": "nodes_proc",
+    "tagtransform-way-function": "ways_proc",
+    "tagtransform-relation-function": "rels_proc",
+    "tagtransform-relation-member-function": "rel_members_proc",
+    "tags": [
+      {"name": "building", "type": "text"},
+      {"name": "shop", "type": "text"},
+      {"name": "amenity", "type": "text"}
     ]
+  },
+  ...
+]
+```
 
 Note that each table has a `name` and can target a single type of geometry
 by setting the `type` to one of `point`, `line` or `polygon`. `tagtransform`
 is used to set the name of the lua script to be used for custom tag processing.
 Within the lua script you may define several methods that will be called
-when processing various tags, these can be named via 
+when processing various tags, these can be named via
 `tagtransform-node-function`, `tagtransform-way-function`,
 `tagtransform-relation-function`, and `tagtransform-relation-member-function`.
 As with the normal top level options within osm2pgsql you can specify any of the
 following: `tablespace-index`, `tablespace-data`, `enable-hstore`,
-`enable-hstore-index`, `enable-multi`, `hstore-match-only`. Hstore colum names
+`enable-hstore-index`, `enable-multi`, `hstore-match-only`. Hstore column names
 may be specified via an array of strings named `hstores`. Finally standard columns
 may be specified via an array of objects named `tags` with each object containing
 a `name` and a postgres `type`. Note you may also set `flags` on each tag as with
 the standard osm2pgsql style file. `flags` is formated exactly as in the style file
-as a string of flag names seprated by commas.
+as a string of flag names separated by commas.
+
+## Polygons ##
+
+Area handling differs slightly from the traditional osm2pgsql C and Lua transforms
+where if a way is added to the polygon or line table depends on if it is closed,
+not just its tagging. All tables with the multi-backend are independent.
+
+All ways in `line` tables are turned into linestrings and what the tag
+transform sets the polygon flag to does not matter. In `polygon` tables ways
+that can be formed into polygons are, and if the polygon flag is not set by the
+tag transform then other ways become linestrings. If the polygon flag is set,
+then linestrings will not be added to the table.
 
 ## Example ##
 An example based on the above is in [multi.lua](../multi.lua) and
diff --git a/docs/osm2pgsql.1 b/docs/osm2pgsql.1
index e3aaec7..b2b5ea1 100644
--- a/docs/osm2pgsql.1
+++ b/docs/osm2pgsql.1
@@ -32,7 +32,7 @@ http://download.geofabrik.de/osm/.
 When operating in "slim" mode (and on a database created in "slim" mode!),
 .B osm2pgsql
 can also process OSM change files (osc files), thereby bringing an existing
-database up to date. 
+database up to date.
 .PP
 .SH OPTIONS
 These programs follow the usual GNU command line syntax, with long
@@ -81,17 +81,14 @@ Store data in proper spherical Mercator (the default).
 \fB\-E\fR|\-\-proj num
 Use projection EPSG:num
 .TP
-\fB\-u\fR|\-\-utf8\-sanitize
-Repair bad UTF\-8 input data (present in planet
-dumps prior to August 2007). Adds about 10% overhead.
-.TP
 \fB\-p\fR|\-\-prefix prefix_string
 Prefix for table names (default: planet_osm).
 .TP
 \fB\-r\fR|\-\-input\-reader format
-Select input format reader. Available choices are \fBlibxml2\fR 
-(default) for OSM XML format files, \fBo5m\fR for o5m formatted file
-and \fBpbf\fR for OSM PBF binary format (may not be available on all platforms).
+Select format of the input file. Available choices are \fBauto\fR
+(default) for autodetecting the format,
+\fBxml\fR for OSM XML format files, \fBo5m\fR for o5m formatted files
+and \fBpbf\fR for OSM PBF binary format.
 .TP
 \fB\-s\fR|\-\-slim
 Store temporary data in the database. Without this mode, all temporary data is stored in
@@ -118,7 +115,7 @@ Only for slim mode: Use up to num many MB of RAM for caching nodes. Giving osm2p
 to store all imported nodes typically greatly increases the speed of the import. Each cached node
 requires 8 bytes of cache, plus about 10% \- 30% overhead. For a current OSM full planet import with
 its ~ 3 billion nodes, a good value would be 27000 if you have enough RAM. If you don't have enough
-RAM, it is likely beneficial to give osm2pgsql close to the full available amount of RAM. Defaults to 800. 
+RAM, it is likely beneficial to give osm2pgsql close to the full available amount of RAM. Defaults to 800.
 .TP
 \fB\  \fR\-\-cache\-strategy strategy
 There are a number of different modes in which osm2pgsql can organize its
@@ -153,12 +150,13 @@ Create a tile expiry list.
 \fB\-o\fR|\-\-expire\-output /path/to/expire.list
 Output file name for expired tiles list.
 .TP
-\fB\-o\fR|\-\-output
+\fB\-O\fR|\-\-output
 Specifies the output back\-end or database schema to use. Currently
 osm2pgsql supports \fBpgsql\fR, \fBgazetteer\fR and \fBnull\fR. \fBpgsql\fR is
 the default output back\-end / schema and is optimized for rendering with Mapnik.
 \fBgazetteer\fR is a db schema optimized for geocoding and is used by Nominatim.
-\fBnull\fR does not write any output and is only useful for testing.
+\fBnull\fR does not write any output and is only useful for testing or with
+\-\-slim for creating slim tables.
 .TP
 \fB\-x\fR|\-\-extra\-attributes
 Include attributes for each object in the database.
diff --git a/docs/pgsql.md b/docs/pgsql.md
index 2ba1a5b..afc1a4f 100644
--- a/docs/pgsql.md
+++ b/docs/pgsql.md
@@ -37,7 +37,7 @@ instead stored in a binary file.
 
 3. If there are tags on a way in the style file as linear but without polygon
    tags, they are written into the lines and, depending on tags, roads tables.
-   
+
    They are also stored by the middle layer.
 
 4. Ways without tags or with polygon tags are stored as "pending" in the
diff --git a/docs/usage.md b/docs/usage.md
index 1cc6c02..3bc9ea5 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -10,7 +10,7 @@ use them.
 * ``--append`` or ``--create`` specify if osm2pgsql is conducting a new import
   or adding to an existing one. ``--slim`` is required with ``--append``.
 
-* ``--input-reader`` specifies the parser if the filetype can't be
+* ``--input-reader`` specifies the format if the filetype can't be
   automatically detected for some reason.
 
 * ``--output`` specifies if the output backend is the default
@@ -30,7 +30,7 @@ that only impact performance.
   store information about ways and relations too. The maximum RAM it is useful
   to set this to in slim mode is 8 bytes * number of nodes / efficiency, where
   efficiency ranges from 50% on small extracts to 80% for a planet.
-  
+
 * ``--number-processes`` sets the number of processes to use. This should
   typically be set to the number of CPU threads, but gains in speed are minimal
   past 8 threads.
@@ -41,7 +41,7 @@ that only impact performance.
 
 * ``--cache-strategy`` sets the cache strategy to use. The defaults are fine
   here, and optimizied uses less RAM than the other options.
-  
+
 ## Database options ##
 
 osm2pgsql supports standard options for how to connect to PostgreSQL. If left
@@ -69,7 +69,7 @@ database if the database server ever crashes, but are faster to import.
 * ``--slim`` causes the middle layer to store node and way information in
   database rather than in memory. It is required for updates and for large
   extracts or the entire planet which will not fit in RAM.
-  
+
 * ``--drop`` discards the slim tables when they are no longer needed in the
   import, significantly reducing disk requirements and saving the time of
   building slim table indexes. A ``--slim --drop`` import is generally the
@@ -102,21 +102,21 @@ osm2pgsql has five hstore options
   a hstore column. With the standard stylesheet this would result in tags like
   highway appearing in a conventional column while tags not in the style like
   ``name:en`` or ``lanes:forward`` would appear only in the hstore column.
-  
+
 * ``--hstore-all`` or ``-j`` adds all tags to a hstore column, even if they're
   already stored in a conventional column. With the standard stylesheet this
   would result in tags like highway appearing in conventional column and the
   hstore column while tags not in the style like ``name:en`` or
   ``lanes:forward`` would appear only in the hstore column.
-  
+
 * ``--hstore-column`` or ``-z``, which adds an additional column for tags
   starting with a specified string, e.g. ``--hstore-column 'name:'`` produces
   a hstore column that contains all ``name:xx`` tags
-  
+
 * ``--hstore-match-only`` modifies the above options and prevents objects from
   being added if they only have tags in the hstore column and no conventional
   tags.
-  
+
 * ``--hstore-add-index`` adds a GIN index to the hstore columns. This can
   speed up arbitrary queries, but for most purposes partial indexes will be
   faster.
@@ -141,7 +141,7 @@ reimporting the database, at the cost of a
   MULTIPOLYGONs are split into multiple POLYGONs. ``--multi-geometry`` can be
   used to [avoid some labeling issues at the cost of speed](http://paulnorman.ca/blog/2014/03/osm2pgsql-multipolygons/).
   It is also typically required for [analysis](analysis.md).
-  
+
 * ``--keep-coastlines`` disables a hard-coded rule that would otherwise
   discard ``natural=coastline`` ways.
 
diff --git a/empty.style b/empty.style
index d06be71..e771fa7 100644
--- a/empty.style
+++ b/empty.style
@@ -1,38 +1,38 @@
 # This osm2pgsql style file is one that will generate no columns from tags
-# It is designed as a starting point for you to develop your own, or for 
+# It is designed as a starting point for you to develop your own, or for
 # use where all OSM tags are in hstore.
 
 # See default.style for documentation on all the flags
 
 # OsmType   Tag                     Type    Flags
-# Insert your own columns here, or change phstore to polygon below
-way         abandoned:aeroway       text    phstore
-way         abandoned:amenity       text    phstore
-way         abandoned:building      text    phstore
-way         abandoned:landuse       text    phstore
-way         abandoned:power         text    phstore
-way         area:highway            text    phstore
-node,way    aeroway                 text    phstore
-node,way    amenity                 text    phstore
-node,way    building                text    phstore
-way         building:part           text    phstore
-node,way    harbour                 text    phstore
-node,way    historic                text    phstore
-node,way    landuse                 text    phstore
-node,way    leisure                 text    phstore
-node,way    man_made                text    phstore
-node,way    military                text    phstore
-node,way    natural                 text    phstore
-node,way    office                  text    phstore
-node,way    place                   text    phstore
-node,way    power                   text    phstore
-node,way    public_transport        text    phstore
-node,way    shop                    text    phstore
-node,way    sport                   text    phstore
-node,way    tourism                 text    phstore
-node,way    water                   text    phstore
-node,way    waterway                text    phstore
-node,way    wetland                 text    phstore
+# Insert your own columns here, or change polygon,nocolumn to polygon below
+way         abandoned:aeroway       text    polygon,nocolumn
+way         abandoned:amenity       text    polygon,nocolumn
+way         abandoned:building      text    polygon,nocolumn
+way         abandoned:landuse       text    polygon,nocolumn
+way         abandoned:power         text    polygon,nocolumn
+way         area:highway            text    polygon,nocolumn
+node,way    aeroway                 text    polygon,nocolumn
+node,way    amenity                 text    polygon,nocolumn
+node,way    building                text    polygon,nocolumn
+way         building:part           text    polygon,nocolumn
+node,way    harbour                 text    polygon,nocolumn
+node,way    historic                text    polygon,nocolumn
+node,way    landuse                 text    polygon,nocolumn
+node,way    leisure                 text    polygon,nocolumn
+node,way    man_made                text    polygon,nocolumn
+node,way    military                text    polygon,nocolumn
+node,way    natural                 text    polygon,nocolumn
+node,way    office                  text    polygon,nocolumn
+node,way    place                   text    polygon,nocolumn
+node,way    power                   text    polygon,nocolumn
+node,way    public_transport        text    polygon,nocolumn
+node,way    shop                    text    polygon,nocolumn
+node,way    sport                   text    polygon,nocolumn
+node,way    tourism                 text    polygon,nocolumn
+node,way    water                   text    polygon,nocolumn
+node,way    waterway                text    polygon,nocolumn
+node,way    wetland                 text    polygon,nocolumn
 node,way    z_order                 int4    linear  # This is calculated during import
 way         way_area                real    linear  # This is calculated during import
 
diff --git a/expire-tiles.cpp b/expire-tiles.cpp
index 3533339..ea52341 100644
--- a/expire-tiles.cpp
+++ b/expire-tiles.cpp
@@ -65,13 +65,12 @@ void destroy_tree(struct expire_tiles::tile * tree) {
  * Returns the number of subtiles which have all their children marked as dirty.
  */
 int _mark_tile(struct expire_tiles::tile ** tree, int x, int y, int zoom, int this_zoom) {
-	int	zoom_diff = zoom - this_zoom;
+	int	zoom_diff = zoom - this_zoom - 1;
 	int	rel_x;
 	int	rel_y;
 	int	complete;
 
 	if (! *tree) *tree = (struct expire_tiles::tile *)calloc(1, sizeof(**tree));
-	zoom_diff = (zoom - this_zoom) - 1;
 	rel_x = (x >> zoom_diff) & 1;
 	rel_y = (y >> zoom_diff) & 1;
 	if (! (*tree)->complete[rel_x][rel_y]) {
@@ -83,7 +82,7 @@ int _mark_tile(struct expire_tiles::tile ** tree, int x, int y, int zoom, int th
 				(*tree)->complete[rel_x][rel_y] = 1;
 				/* We can destroy the subtree to save memory now all the children are dirty */
 				destroy_tree((*tree)->subtiles[rel_x][rel_y]);
-				(*tree)->subtiles[rel_x][rel_y] = NULL;
+				(*tree)->subtiles[rel_x][rel_y] = nullptr;
 			}
 		}
 	}
@@ -129,7 +128,7 @@ struct tile_output_file : public expire_tiles::tile_output {
   tile_output_file(const std::string &expire_tiles_filename)
     : outcount(0)
     , outfile(fopen(expire_tiles_filename.c_str(), "a")) {
-    if (outfile == NULL) {
+    if (outfile == nullptr) {
       fprintf(stderr, "Failed to open expired tiles file (%s).  Tile expiry list will not be written!\n", strerror(errno));
     }
   }
@@ -159,28 +158,28 @@ void _output_and_destroy_tree(expire_tiles::tile_output *output, struct expire_t
 	out = output;
 	if ((tree->complete[0][0]) && output) {
 		output->output_dirty_tile(sub_x + 0, sub_y + 0, this_zoom + 1, min_zoom);
-		out = NULL;
+		out = nullptr;
 	}
 	if (tree->subtiles[0][0]) _output_and_destroy_tree(out, tree->subtiles[0][0], sub_x + 0, sub_y + 0, this_zoom + 1, min_zoom);
 
 	out = output;
 	if ((tree->complete[0][1]) && output) {
 		output->output_dirty_tile(sub_x + 0, sub_y + 1, this_zoom + 1, min_zoom);
-		out = NULL;
+		out = nullptr;
 	}
 	if (tree->subtiles[0][1]) _output_and_destroy_tree(out, tree->subtiles[0][1], sub_x + 0, sub_y + 1, this_zoom + 1, min_zoom);
 
 	out = output;
 	if ((tree->complete[1][0]) && output) {
 		output->output_dirty_tile(sub_x + 1, sub_y + 0, this_zoom + 1, min_zoom);
-		out = NULL;
+		out = nullptr;
 	}
 	if (tree->subtiles[1][0]) _output_and_destroy_tree(out, tree->subtiles[1][0], sub_x + 1, sub_y + 0, this_zoom + 1, min_zoom);
 
 	out = output;
 	if ((tree->complete[1][1]) && output) {
 		output->output_dirty_tile(sub_x + 1, sub_y + 1, this_zoom + 1, min_zoom);
-		out = NULL;
+		out = nullptr;
 	}
 	if (tree->subtiles[1][1]) _output_and_destroy_tree(out, tree->subtiles[1][1], sub_x + 1, sub_y + 1, this_zoom + 1, min_zoom);
 
@@ -191,11 +190,11 @@ void _output_and_destroy_tree(expire_tiles::tile_output *output, struct expire_t
 // number of completed subtrees.
 int _tree_merge(struct expire_tiles::tile **a,
                 struct expire_tiles::tile **b) {
-  if (*a == NULL) {
+  if (*a == nullptr) {
     *a = *b;
-    *b = NULL;
+    *b = nullptr;
 
-  } else if (*b != NULL) {
+  } else if (*b != nullptr) {
     for (int x = 0; x < 2; ++x) {
       for (int y = 0; y < 2; ++y) {
         // if b is complete on a subtree, then the merged tree must
@@ -203,7 +202,7 @@ int _tree_merge(struct expire_tiles::tile **a,
         if ((*b)->complete[x][y]) {
           (*a)->complete[x][y] = (*b)->complete[x][y];
           destroy_tree((*a)->subtiles[x][y]);
-          (*a)->subtiles[x][y] = NULL;
+          (*a)->subtiles[x][y] = nullptr;
 
           // but if a is already complete, don't bother moving across
           // anything
@@ -213,12 +212,12 @@ int _tree_merge(struct expire_tiles::tile **a,
           if (complete >= 4) {
             (*a)->complete[x][y] = 1;
             destroy_tree((*a)->subtiles[x][y]);
-            (*a)->subtiles[x][y] = NULL;
+            (*a)->subtiles[x][y] = nullptr;
           }
         }
 
         destroy_tree((*b)->subtiles[x][y]);
-        (*b)->subtiles[x][y] = NULL;
+        (*b)->subtiles[x][y] = nullptr;
       }
     }
   }
@@ -227,7 +226,7 @@ int _tree_merge(struct expire_tiles::tile **a,
   int a_complete = 0;
   for (int x = 0; x < 2; ++x) {
     for (int y = 0; y < 2; ++y) {
-      if ((*a != NULL) && ((*a)->complete[x][y])) {
+      if ((*a != nullptr) && ((*a)->complete[x][y])) {
         ++a_complete;
       }
     }
@@ -240,7 +239,7 @@ int _tree_merge(struct expire_tiles::tile **a,
 
 void expire_tiles::output_and_destroy(tile_output *output) {
     _output_and_destroy_tree(output, dirty, 0, 0, 0, Options->expire_tiles_zoom_min);
-    dirty = NULL;
+    dirty = nullptr;
 }
 
 void expire_tiles::output_and_destroy() {
@@ -252,15 +251,15 @@ void expire_tiles::output_and_destroy() {
 }
 
 expire_tiles::~expire_tiles() {
-  if (dirty != NULL) {
+  if (dirty != nullptr) {
     destroy_tree(dirty);
-    dirty = NULL;
+    dirty = nullptr;
   }
 }
 
 expire_tiles::expire_tiles(const struct options_t *options)
     : map_width(0), tile_width(0), Options(options),
-      dirty(NULL)
+      dirty(nullptr)
 {
 	if (Options->expire_tiles_zoom < 0) return;
 	map_width = 1 << Options->expire_tiles_zoom;
@@ -465,14 +464,14 @@ void expire_tiles::from_xnodes_line(const multinodelist_t &xnodes)
         from_nodes_line(*it);
 }
 
-void expire_tiles::from_wkt(const char * wkt, osmid_t osm_id)
+void expire_tiles::from_wkb(const char* wkb, osmid_t osm_id)
 {
     if (Options->expire_tiles_zoom < 0) return;
 
     multinodelist_t xnodes;
-    int polygon;
+    bool polygon;
 
-    if (!geometry_builder::parse_wkt(wkt, xnodes, &polygon)) {
+    if (geometry_builder::parse_wkb(wkb, xnodes, &polygon) == 0) {
         if (polygon)
             from_xnodes_poly(xnodes, osm_id);
         else
@@ -484,7 +483,7 @@ void expire_tiles::from_wkt(const char * wkt, osmid_t osm_id)
  * Expire tiles based on an osm element.
  * What type of element (node, line, polygon) osm_id refers to depends on
  * sql_conn. Each type of table has its own sql_conn and the prepared statement
- * get_wkt refers to the appropriate table.
+ * get_wkb refers to the appropriate table.
  *
  * The function returns -1 if expiry is not enabled. Otherwise it returns the number
  * of elements that refer to the osm_id.
@@ -496,15 +495,15 @@ int expire_tiles::from_db(table_t* table, osmid_t osm_id) {
         return -1;
 
     //grab the geom for this id
-    boost::shared_ptr<table_t::wkt_reader> wkts = table->get_wkt_reader(osm_id);
+    auto wkbs = table->get_wkb_reader(osm_id);
 
     //dirty the stuff
-    const char* wkt = NULL;
-    while((wkt = wkts->get_next()))
-        from_wkt(wkt, osm_id);
+    const char* wkb = nullptr;
+    while((wkb = wkbs.get_next()))
+        from_wkb(wkb, osm_id);
 
     //return how many rows were affected
-    return wkts->get_count();
+    return wkbs.get_count();
 }
 
 void expire_tiles::merge_and_destroy(expire_tiles &other) {
@@ -523,5 +522,5 @@ void expire_tiles::merge_and_destroy(expire_tiles &other) {
   _tree_merge(&dirty, &other.dirty);
 
   destroy_tree(other.dirty);
-  other.dirty = NULL;
+  other.dirty = nullptr;
 }
diff --git a/expire-tiles.hpp b/expire-tiles.hpp
index 64133b6..8a21653 100644
--- a/expire-tiles.hpp
+++ b/expire-tiles.hpp
@@ -17,7 +17,7 @@ struct expire_tiles : public boost::noncopyable {
     int from_bbox(double min_lon, double min_lat, double max_lon, double max_lat);
     void from_nodes_line(const nodelist_t &nodes);
     void from_nodes_poly(const nodelist_t &nodes, osmid_t osm_id);
-    void from_wkt(const char * wkt, osmid_t osm_id);
+    void from_wkb(const char* wkb, osmid_t osm_id);
     int from_db(table_t* table, osmid_t osm_id);
 
     struct tile {
diff --git a/geometry-builder.cpp b/geometry-builder.cpp
index a0233e6..dd848a9 100644
--- a/geometry-builder.cpp
+++ b/geometry-builder.cpp
@@ -24,9 +24,11 @@
 #include <algorithm>
 #include <cmath>
 #include <cstddef>
+#include <sstream>
 #include <stdexcept>
 #include <memory>
 #include <new>
+#include <numeric>
 
 #if defined(__CYGWIN__)
 #define GEOS_INLINE
@@ -45,18 +47,19 @@
 #include <geos/geom/MultiLineString.h>
 #include <geos/geom/Polygon.h>
 #include <geos/geom/MultiPolygon.h>
-#include <geos/io/WKTReader.h>
-#include <geos/io/WKTWriter.h>
+#include <geos/io/WKBReader.h>
+#include <geos/io/WKBWriter.h>
 #include <geos/util/GEOSException.h>
 #include <geos/opLinemerge.h>
 using namespace geos::geom;
-using namespace geos::io;
 using namespace geos::util;
 using namespace geos::operation::linemerge;
 
 #include "geometry-builder.hpp"
+#include "reprojection.hpp"
 
-typedef std::auto_ptr<Geometry> geom_ptr;
+typedef std::unique_ptr<Geometry> geom_ptr;
+typedef std::unique_ptr<CoordinateSequence> coord_ptr;
 
 namespace {
 
@@ -71,13 +74,109 @@ void coords2nodes(CoordinateSequence * coords, nodelist_t &nodes)
     }
 }
 
+coord_ptr nodes2coords(GeometryFactory &gf, const nodelist_t &nodes)
+{
+    coord_ptr coords(gf.getCoordinateSequenceFactory()->create(size_t(0), size_t(2)));
+
+    for (const auto& nd: nodes) {
+        coords->add(Coordinate(nd.lon, nd.lat), 0);
+    }
+
+    return coords;
+}
+
+geom_ptr create_multi_line(GeometryFactory &gf, const multinodelist_t &xnodes)
+{
+    // XXX leaks memory if an exception is thrown
+    std::unique_ptr<std::vector<Geometry*> > lines(new std::vector<Geometry*>);
+    lines->reserve(xnodes.size());
+
+    for (const auto& nodes: xnodes) {
+        auto coords = nodes2coords(gf, nodes);
+        if (coords->getSize() > 1) {
+            lines->push_back(gf.createLineString(coords.release()));
+        }
+    }
+
+    return geom_ptr(gf.createMultiLineString(lines.release()));
+}
+
+bool is_polygon_line(CoordinateSequence * coords)
+{
+    return (coords->getSize() >= 4)
+           && (coords->getAt(coords->getSize() - 1).equals2D(coords->getAt(0)));
+}
+
+/**
+ * Reprojects given Linear Ring from target projection to spherical mercator.
+ * Caller takes ownership of return value.
+ */
+LinearRing* reproject_linearring(const LineString *ls, const reprojection *proj)
+{
+    auto *gf = ls->getFactory();
+    coord_ptr coords(gf->getCoordinateSequenceFactory()->create(size_t(0), size_t(2)));
+    for (auto i : *(ls->getCoordinatesRO()->toVector())) {
+        Coordinate c(i.x, i.y);
+        proj->target_to_tile(&c.y, &c.x);
+        coords->add(c);
+    }
+    return gf->createLinearRing(coords.release());
+}
+
+
+/**
+ * Computes area of given polygonal geometry.
+ * \return the area in projected units, or in EPSG 3857 if area reprojection is enabled
+ */
+double get_area(const geos::geom::Geometry *geom, reprojection *proj)
+{
+    // reprojection is not necessary, or has not been asked for.
+    if (!proj) {
+        return geom->getArea();
+    }
+
+    // MultiPolygon - return sum of individual areas
+    if (const auto *multi = dynamic_cast<const MultiPolygon *>(geom)) {
+        return std::accumulate(multi->begin(), multi->end(), 0.0,
+                               [=](double a, const Geometry *g) {
+                                 return a + get_area(g, proj);
+                               });
+    }
+
+    const auto *poly = dynamic_cast<const geos::geom::Polygon *>(geom);
+    if (!poly) {
+        return 0.0;
+    }
+
+    // standard polygon - reproject rings individually, then assemble polygon and
+    // compute area.
+
+    const auto *ext = poly->getExteriorRing();
+    std::unique_ptr<LinearRing> projectedExt(reproject_linearring(ext, proj));
+    auto nholes = poly->getNumInteriorRing();
+    std::unique_ptr<std::vector<Geometry *> > projectedHoles(new std::vector<Geometry *>);
+    for (std::size_t i=0; i < nholes; i++) {
+        auto* hole = poly->getInteriorRingN(i);
+        projectedHoles->push_back(reproject_linearring(hole, proj));
+    }
+    const geom_ptr projectedPoly(poly->getFactory()->createPolygon(projectedExt.release(), projectedHoles.release()));
+
+    return projectedPoly->getArea();
+}
+
+
 struct polygondata
 {
-    Polygon*        polygon;
-    LinearRing*     ring;
+    std::unique_ptr<Polygon>    polygon;
+    std::unique_ptr<LinearRing> ring;
     double          area;
-    int             iscontained;
+    bool            iscontained;
     unsigned        containedbyid;
+
+    polygondata(std::unique_ptr<Polygon> p, LinearRing* r, double a)
+    : polygon(std::move(p)), ring(r), area(a),
+      iscontained(false), containedbyid(0)
+    {}
 };
 
 struct polygondata_comparearea {
@@ -88,40 +187,57 @@ struct polygondata_comparearea {
 
 } // anonymous namespace
 
-geometry_builder::maybe_wkt_t geometry_builder::get_wkt_simple(const nodelist_t &nodes, int polygon) const
+
+void geometry_builder::pg_geom_t::set(const geos::geom::Geometry *g, bool poly,
+                                      reprojection *p)
 {
-    GeometryFactory gf;
-    std::auto_ptr<CoordinateSequence> coords(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2));
+    geos::io::WKBWriter writer(2, getMachineByteOrder(), true);
+    std::stringstream stream(std::ios_base::out);
+    writer.writeHEX(*g, stream);
+    geom = stream.str();
+
+    if (valid()) {
+        area = poly ? get_area(g, p) : 0;
+        polygon = poly;
+    }
+}
 
-    try
-    {
-        for (nodelist_t::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
-            coords->add(Coordinate(it->lon, it->lat), 0);
+geom_ptr geometry_builder::create_simple_poly(GeometryFactory &gf,
+                                              std::unique_ptr<CoordinateSequence> coords) const
+{
+    std::unique_ptr<LinearRing> shell(gf.createLinearRing(coords.release()));
+    std::unique_ptr<std::vector<Geometry *> > empty(new std::vector<Geometry *>);
+    geom_ptr geom(gf.createPolygon(shell.release(), empty.release()));
+
+    if (!geom->isValid()) {
+        if (excludepoly) {
+            throw std::runtime_error("Excluding broken polygon.");
+        } else {
+            geom = geom_ptr(geom->buffer(0));
         }
+    }
+    geom->normalize(); // Fix direction of ring
 
-        maybe_wkt_t wkt(new geometry_builder::wkt_t());
-        geom_ptr geom;
-        if (polygon && (coords->getSize() >= 4) && (coords->getAt(coords->getSize() - 1).equals2D(coords->getAt(0)))) {
-            std::auto_ptr<LinearRing> shell(gf.createLinearRing(coords.release()));
-            geom = geom_ptr(gf.createPolygon(shell.release(), new std::vector<Geometry *>));
-            if (!geom->isValid()) {
-                if (excludepoly) {
-                    throw std::runtime_error("Excluding broken polygon.");
-                } else {
-                    geom = geom_ptr(geom->buffer(0));
-                }
-            }
-            geom->normalize(); // Fix direction of ring
-            wkt->area = geom->getArea();
+    return geom;
+}
+
+geometry_builder::pg_geom_t geometry_builder::get_wkb_simple(const nodelist_t &nodes, int polygon) const
+{
+    pg_geom_t wkb;
+
+    try
+    {
+        GeometryFactory gf;
+        auto coords = nodes2coords(gf, nodes);
+        if (polygon && is_polygon_line(coords.get())) {
+            auto geom = create_simple_poly(gf, std::move(coords));
+            wkb.set(geom.get(), true, projection);
         } else {
             if (coords->getSize() < 2)
                 throw std::runtime_error("Excluding degenerate line.");
-            geom = geom_ptr(gf.createLineString(coords.release()));
-            wkt->area = 0;
+            geom_ptr geom(gf.createLineString(coords.release()));
+            wkb.set(geom.get(), false);
         }
-
-        wkt->geom = WKTWriter().write(geom.get());
-        return wkt;
     }
     catch (const std::bad_alloc&)
     {
@@ -137,51 +253,30 @@ geometry_builder::maybe_wkt_t geometry_builder::get_wkt_simple(const nodelist_t
         std::cerr << std::endl << "Exception caught processing way" << std::endl;
     }
 
-    return maybe_wkt_t();
+    return wkb;
 }
 
-geometry_builder::maybe_wkts_t geometry_builder::get_wkt_split(const nodelist_t &nodes, int polygon, double split_at) const
+geometry_builder::pg_geoms_t geometry_builder::get_wkb_split(const nodelist_t &nodes, int polygon, double split_at) const
 {
-    GeometryFactory gf;
-    std::auto_ptr<CoordinateSequence> coords(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2));
-    WKTWriter writer;
     //TODO: use count to get some kind of hint of how much we should reserve?
-    maybe_wkts_t wkts(new std::vector<geometry_builder::wkt_t>);
+    pg_geoms_t wkbs;
 
     try
     {
-        for (nodelist_t::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
-            coords->add(Coordinate(it->lon, it->lat), 0);
-        }
-
-        geom_ptr geom;
-        if (polygon && (coords->getSize() >= 4) && (coords->getAt(coords->getSize() - 1).equals2D(coords->getAt(0)))) {
-            std::auto_ptr<LinearRing> shell(gf.createLinearRing(coords.release()));
-            geom = geom_ptr(gf.createPolygon(shell.release(), new std::vector<Geometry *>));
-            if (!geom->isValid()) {
-                if (excludepoly) {
-                    throw std::runtime_error("Excluding broken polygon.");
-                } else {
-                    geom = geom_ptr(geom->buffer(0));
-                }
-            }
-            geom->normalize(); // Fix direction of ring
-
-            //copy of an empty one should be cheapest
-            wkts->push_back(geometry_builder::wkt_t());
-            //then we set on the one we already have
-            wkts->back().geom = writer.write(geom.get());
-            wkts->back().area = geom->getArea();
+        GeometryFactory gf;
+        auto coords = nodes2coords(gf, nodes);
 
+        if (polygon && is_polygon_line(coords.get())) {
+            auto geom = create_simple_poly(gf, std::move(coords));
+            wkbs.emplace_back(geom.get(), true, projection);
         } else {
             if (coords->getSize() < 2)
                 throw std::runtime_error("Excluding degenerate line.");
 
             double distance = 0;
-            std::auto_ptr<CoordinateSequence> segment;
-            segment = std::auto_ptr<CoordinateSequence>(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2));
+            std::unique_ptr<CoordinateSequence> segment(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2));
             segment->add(coords->getAt(0));
-            for(unsigned i=1; i<coords->getSize(); i++) {
+            for(size_t i=1; i<coords->getSize(); i++) {
                 const Coordinate this_pt = coords->getAt(i);
                 const Coordinate prev_pt = coords->getAt(i-1);
                 const double delta = this_pt.distance(prev_pt);
@@ -190,22 +285,18 @@ geometry_builder::maybe_wkts_t geometry_builder::get_wkt_split(const nodelist_t
                 // length of the line in `segment` over the `split_at` distance.
 
                 if (distance + delta > split_at) {
-                    const size_t splits = std::floor((distance + delta) / split_at);
+                    const size_t splits = (size_t) std::floor((distance + delta) / split_at);
                     // use the splitting distance to split the current segment up
                     // into as many parts as necessary to keep each part below
                     // the `split_at` distance.
-                    for (size_t i = 0; i < splits; ++i) {
-                        double frac = (double(i + 1) * split_at - distance) / delta;
+                    for (size_t j = 0; j < splits; ++j) {
+                        double frac = (double(j + 1) * split_at - distance) / delta;
                         const Coordinate interpolated(frac * (this_pt.x - prev_pt.x) + prev_pt.x,
                                                       frac * (this_pt.y - prev_pt.y) + prev_pt.y);
                         segment->add(interpolated);
-                        geom_ptr geom = geom_ptr(gf.createLineString(segment.release()));
+                        geom_ptr geom(gf.createLineString(segment.release()));
 
-                        //copy of an empty one should be cheapest
-                        wkts->push_back(geometry_builder::wkt_t());
-                        //then we set on the one we already have
-                        wkts->back().geom = writer.write(geom.get());
-                        wkts->back().area = 0;
+                        wkbs.emplace_back(geom.get(), false);
 
                         segment.reset(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2));
                         segment->add(interpolated);
@@ -225,15 +316,9 @@ geometry_builder::maybe_wkts_t geometry_builder::get_wkt_split(const nodelist_t
 
                 // on the last iteration, close out the line.
                 if (i == coords->getSize()-1) {
-                    geom_ptr geom = geom_ptr(gf.createLineString(segment.release()));
-
-                    //copy of an empty one should be cheapest
-                    wkts->push_back(geometry_builder::wkt_t());
-                    //then we set on the one we already have
-                    wkts->back().geom = writer.write(geom.get());
-                    wkts->back().area = 0;
+                    geom_ptr geom(gf.createLineString(segment.release()));
 
-                    segment.reset(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2));
+                    wkbs.emplace_back(geom.get(), false);
                 }
             }
         }
@@ -251,172 +336,126 @@ geometry_builder::maybe_wkts_t geometry_builder::get_wkt_split(const nodelist_t
     {
         std::cerr << std::endl << "Exception caught processing way" << std::endl;
     }
-    return wkts;
+    return wkbs;
 }
 
-int geometry_builder::parse_wkt(const char * wkt, multinodelist_t &nodes, int *polygon) {
+int geometry_builder::parse_wkb(const char* wkb, multinodelist_t &nodes, bool *polygon) {
     GeometryFactory gf;
-    WKTReader reader(&gf);
-    std::string wkt_string(wkt);
-    GeometryCollection * gc;
-    CoordinateSequence * coords;
-    size_t num_geometries;
-
-    *polygon = 0;
-    try {
-        Geometry * geometry = reader.read(wkt_string);
-        switch (geometry->getGeometryTypeId()) {
-            // Single geometries
-            case GEOS_POLYGON:
-                // Drop through
-            case GEOS_LINEARRING:
-                *polygon = 1;
-                // Drop through
-            case GEOS_POINT:
-                // Drop through
-            case GEOS_LINESTRING:
-                nodes.push_back(nodelist_t());
-                coords = geometry->getCoordinates();
-                coords2nodes(coords, nodes.back());
-                delete coords;
-                break;
-            // Geometry collections
-            case GEOS_MULTIPOLYGON:
-                *polygon = 1;
-                // Drop through
-            case GEOS_MULTIPOINT:
-                // Drop through
-            case GEOS_MULTILINESTRING:
-                gc = dynamic_cast<GeometryCollection *>(geometry);
-                num_geometries = gc->getNumGeometries();
-                nodes.assign(num_geometries, nodelist_t());
-                for (size_t i = 0; i < num_geometries; i++) {
-                    const Geometry *subgeometry = gc->getGeometryN(i);
-                    coords = subgeometry->getCoordinates();
-                    coords2nodes(coords, nodes[i]);
-                    delete coords;
-                }
-                break;
-            default:
-                std::cerr << std::endl << "unexpected object type while processing PostGIS data" << std::endl;
-                delete geometry;
-                return -1;
+    geos::io::WKBReader reader(gf);
+
+    *polygon = false;
+    std::stringstream stream(wkb, std::ios_base::in);
+    geom_ptr geometry(reader.readHEX(stream));
+    switch (geometry->getGeometryTypeId()) {
+        // Single geometries
+        case GEOS_POLYGON:
+            // Drop through
+        case GEOS_LINEARRING:
+            *polygon = true;
+            // Drop through
+        case GEOS_POINT:
+            // Drop through
+        case GEOS_LINESTRING:
+        {
+            nodes.push_back(nodelist_t());
+            coord_ptr coords(geometry->getCoordinates());
+            coords2nodes(coords.get(), nodes.back());
+            break;
+        }
+        // Geometry collections
+        case GEOS_MULTIPOLYGON:
+            *polygon = true;
+            // Drop through
+        case GEOS_MULTIPOINT:
+            // Drop through
+        case GEOS_MULTILINESTRING:
+        {
+            auto gc = dynamic_cast<GeometryCollection *>(geometry.get());
+            size_t num_geometries = gc->getNumGeometries();
+            nodes.assign(num_geometries, nodelist_t());
+            for (size_t i = 0; i < num_geometries; i++) {
+                const Geometry *subgeometry = gc->getGeometryN(i);
+                coord_ptr coords(subgeometry->getCoordinates());
+                coords2nodes(coords.get(), nodes[i]);
+            }
+            break;
         }
-        delete geometry;
-    } catch (...) {
-        std::cerr << std::endl << "Exception caught parsing PostGIS data" << std::endl;
-        return -1;
+        default:
+            std::cerr << std::endl << "unexpected object type while processing PostGIS data" << std::endl;
+            return -1;
     }
+
     return 0;
 }
 
-geometry_builder::maybe_wkts_t geometry_builder::build_polygons(const multinodelist_t &xnodes,
-                                                                bool enable_multi, osmid_t osm_id) const
+geometry_builder::pg_geoms_t geometry_builder::build_polygons(const multinodelist_t &xnodes,
+                                                              bool enable_multi, osmid_t osm_id) const
 {
-    std::auto_ptr<std::vector<Geometry*> > lines(new std::vector<Geometry*>);
-    GeometryFactory gf;
-    geom_ptr geom;
-    geos::geom::prep::PreparedGeometryFactory pgf;
-
-    maybe_wkts_t wkts(new std::vector<geometry_builder::wkt_t>);
+    pg_geoms_t wkbs;
 
     try
     {
-        for (multinodelist_t::const_iterator it = xnodes.begin(); it != xnodes.end(); ++it) {
-            std::auto_ptr<CoordinateSequence> coords(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2));
-            for (nodelist_t::const_iterator node = it->begin(); node != it->end(); ++node) {
-                Coordinate c;
-                c.x = node->lon;
-                c.y = node->lat;
-                coords->add(c, 0);
-            }
-            if (coords->getSize() > 1) {
-                geom = geom_ptr(gf.createLineString(coords.release()));
-                lines->push_back(geom.release());
-            }
-        }
+        GeometryFactory gf;
+        geom_ptr mline = create_multi_line(gf, xnodes);
 
-        //geom_ptr segment(0);
-        geom_ptr mline (gf.createMultiLineString(lines.release()));
         //geom_ptr noded (segment->Union(mline.get()));
         LineMerger merger;
         //merger.add(noded.get());
         merger.add(mline.get());
-        std::auto_ptr<std::vector<LineString *> > merged(merger.getMergedLineStrings());
-        WKTWriter writer;
+        std::unique_ptr<std::vector<LineString *>> merged(merger.getMergedLineStrings());
 
         // Procces ways into lines or simple polygon list
-        std::vector<polygondata> polys(merged->size());
-
-        unsigned totalpolys = 0;
-        for (unsigned i=0 ;i < merged->size(); ++i)
-        {
-            std::auto_ptr<LineString> pline ((*merged ) [i]);
-            if (pline->getNumPoints() > 3 && pline->isClosed())
-            {
-                polys[totalpolys].polygon = gf.createPolygon(gf.createLinearRing(pline->getCoordinates()),0);
-                polys[totalpolys].ring = gf.createLinearRing(pline->getCoordinates());
-                polys[totalpolys].area = polys[totalpolys].polygon->getArea();
-                polys[totalpolys].iscontained = 0;
-                polys[totalpolys].containedbyid = 0;
-                if (polys[totalpolys].area > 0.0)
-                    totalpolys++;
-                else {
-                    delete(polys[totalpolys].polygon);
-                    delete(polys[totalpolys].ring);
+        std::vector<polygondata> polys;
+        polys.reserve(merged->size());
+
+        for (auto *line: *merged) {
+            // stuff into unique pointer for auto-destruct
+            std::unique_ptr<LineString> pline(line);
+            if (pline->getNumPoints() > 3 && pline->isClosed()) {
+                std::unique_ptr<Polygon> poly(gf.createPolygon(gf.createLinearRing(pline->getCoordinates()),0));
+                double area = get_area(poly.get(), projection);
+                if (area > 0.0) {
+                    polys.emplace_back(std::move(poly),
+                                       gf.createLinearRing(pline->getCoordinates()),
+                                       area);
                 }
             }
         }
 
-        if (totalpolys)
+        if (!polys.empty())
         {
-            std::sort(polys.begin(), polys.begin() + totalpolys, polygondata_comparearea());
+            std::sort(polys.begin(), polys.end(), polygondata_comparearea());
 
             unsigned toplevelpolygons = 0;
             int istoplevelafterall;
+            size_t totalpolys = polys.size();
 
+            geos::geom::prep::PreparedGeometryFactory pgf;
             for (unsigned i=0 ;i < totalpolys; ++i)
             {
-                if (polys[i].iscontained != 0) continue;
+                if (polys[i].iscontained) continue;
                 toplevelpolygons++;
-                const geos::geom::prep::PreparedGeometry* preparedtoplevelpolygon = pgf.create(polys[i].polygon);
+                const geos::geom::prep::PreparedGeometry* preparedtoplevelpolygon = pgf.create(polys[i].polygon.get());
 
                 for (unsigned j=i+1; j < totalpolys; ++j)
                 {
                     // Does preparedtoplevelpolygon contain the smaller polygon[j]?
-                    if (polys[j].containedbyid == 0 && preparedtoplevelpolygon->contains(polys[j].polygon))
+                    if (polys[j].containedbyid == 0 && preparedtoplevelpolygon->contains(polys[j].polygon.get()))
                     {
                         // are we in a [i] contains [k] contains [j] situation
                         // which would actually make j top level
                         istoplevelafterall = 0;
                         for (unsigned k=i+1; k < j; ++k)
                         {
-                            if (polys[k].iscontained && polys[k].containedbyid == i && polys[k].polygon->contains(polys[j].polygon))
+                            if (polys[k].iscontained && polys[k].containedbyid == i && polys[k].polygon->contains(polys[j].polygon.get()))
                             {
                                 istoplevelafterall = 1;
                                 break;
                             }
-#if 0
-                            else if (polys[k].polygon->intersects(polys[j].polygon) || polys[k].polygon->touches(polys[j].polygon))
-                            {
-                                // FIXME: This code does not work as intended
-                                // It should be setting the polys[k].ring in order to update this object
-                                // but the value of polys[k].polygon calculated is normally NULL
-
-                                // Add polygon this polygon (j) to k since they intersect
-                                // Mark ourselfs to be dropped (2), delete the original k
-                                Geometry* polyunion = polys[k].polygon->Union(polys[j].polygon);
-                                delete(polys[k].polygon);
-                                polys[k].polygon = dynamic_cast<Polygon*>(polyunion);
-                                polys[j].iscontained = 2; // Drop
-                                istoplevelafterall = 2;
-                                break;
-                            }
-#endif
                         }
                         if (istoplevelafterall == 0)
                         {
-                            polys[j].iscontained = 1;
+                            polys[j].iscontained = true;
                             polys[j].containedbyid = i;
                         }
                     }
@@ -426,24 +465,24 @@ geometry_builder::maybe_wkts_t geometry_builder::build_polygons(const multinodel
             // polys now is a list of polygons tagged with which ones are inside each other
 
             // List of polygons for multipolygon
-            std::auto_ptr<std::vector<Geometry*> > polygons(new std::vector<Geometry*>);
+            std::unique_ptr<std::vector<Geometry*>> polygons(new std::vector<Geometry*>);
 
             // For each top level polygon create a new polygon including any holes
             for (unsigned i=0 ;i < totalpolys; ++i)
             {
-                if (polys[i].iscontained != 0) continue;
+                if (polys[i].iscontained) continue;
 
                 // List of holes for this top level polygon
-                std::auto_ptr<std::vector<Geometry*> > interior(new std::vector<Geometry*>);
+                std::unique_ptr<std::vector<Geometry*> > interior(new std::vector<Geometry*>);
                 for (unsigned j=i+1; j < totalpolys; ++j)
                 {
-                   if (polys[j].iscontained == 1 && polys[j].containedbyid == i)
+                   if (polys[j].iscontained && polys[j].containedbyid == i)
                    {
-                       interior->push_back(polys[j].ring);
+                       interior->push_back(polys[j].ring.release());
                    }
                 }
 
-                Polygon* poly(gf.createPolygon(polys[i].ring, interior.release()));
+                Polygon* poly(gf.createPolygon(polys[i].ring.release(), interior.release()));
                 poly->normalize();
                 polygons->push_back(poly);
             }
@@ -452,214 +491,142 @@ geometry_builder::maybe_wkts_t geometry_builder::build_polygons(const multinodel
             if ((toplevelpolygons > 1) && enable_multi)
             {
                 geom_ptr multipoly(gf.createMultiPolygon(polygons.release()));
-                if (!multipoly->isValid() && (excludepoly == 0)) {
+                if (!multipoly->isValid() && !excludepoly) {
                     multipoly = geom_ptr(multipoly->buffer(0));
                 }
                 multipoly->normalize();
 
-                if ((excludepoly == 0) || (multipoly->isValid()))
-                {
-                    //copy of an empty one should be cheapest
-                    wkts->push_back(geometry_builder::wkt_t());
-                    //then we set on the one we already have
-                    wkts->back().geom = writer.write(multipoly.get());
-                    wkts->back().area = multipoly->getArea();
+                if ((excludepoly == 0) || (multipoly->isValid())) {
+                    wkbs.emplace_back(multipoly.get(), true, projection);
                 }
             }
             else
             {
-                for(unsigned i=0; i<toplevelpolygons; i++)
-                {
-                    Geometry* poly = dynamic_cast<Geometry*>(polygons->at(i));
-                    if (!poly->isValid() && (excludepoly == 0)) {
-                        poly = dynamic_cast<Geometry*>(poly->buffer(0));
+                for(unsigned i=0; i<toplevelpolygons; i++) {
+                    geom_ptr poly(polygons->at(i));
+                    if (!poly->isValid() && !excludepoly) {
+                        poly = geom_ptr(poly->buffer(0));
                         poly->normalize();
                     }
-                    if ((excludepoly == 0) || (poly->isValid()))
-                    {
-                        //copy of an empty one should be cheapest
-                        wkts->push_back(geometry_builder::wkt_t());
-                        //then we set on the one we already have
-                        wkts->back().geom = writer.write(poly);
-                        wkts->back().area = poly->getArea();
+                    if ((excludepoly == 0) || (poly->isValid())) {
+                        wkbs.emplace_back(poly.get(), true, projection);
                     }
-                    delete(poly);
                 }
             }
         }
-
-        for (unsigned i=0; i < totalpolys; ++i)
-        {
-            delete(polys[i].polygon);
-        }
     }//TODO: don't show in message id when osm_id == -1
     catch (const std::exception& e)
     {
-        std::cerr << std::endl << "Standard exception processing way_id="<< osm_id << ": " << e.what()  << std::endl;
+        std::cerr << std::endl << "Standard exception processing relation_id="<< osm_id << ": " << e.what()  << std::endl;
     }
     catch (...)
     {
-        std::cerr << std::endl << "Exception caught processing way id=" << osm_id << std::endl;
+        std::cerr << std::endl << "Exception caught processing relation id=" << osm_id << std::endl;
     }
 
-    return wkts;
+    return wkbs;
 }
 
-geometry_builder::maybe_wkt_t geometry_builder::build_multilines(const multinodelist_t &xnodes, osmid_t osm_id) const
+geometry_builder::pg_geom_t geometry_builder::build_multilines(const multinodelist_t &xnodes, osmid_t osm_id) const
 {
-    std::auto_ptr<std::vector<Geometry*> > lines(new std::vector<Geometry*>);
-    GeometryFactory gf;
-    geom_ptr geom;
-
-    maybe_wkt_t wkt(new geometry_builder::wkt_t());
+    pg_geom_t wkb;
 
     try
     {
-        for (multinodelist_t::const_iterator it = xnodes.begin(); it != xnodes.end(); ++it) {
-            std::auto_ptr<CoordinateSequence> coords(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2));
-            for (nodelist_t::const_iterator node = it->begin(); node != it->end(); ++node) {
-                Coordinate c;
-                c.x = node->lon;
-                c.y = node->lat;
-                coords->add(c, 0);
-            }
-            if (coords->getSize() > 1) {
-                geom = geom_ptr(gf.createLineString(coords.release()));
-                lines->push_back(geom.release());
-            }
-        }
-
-        //geom_ptr segment(0);
-        geom_ptr mline (gf.createMultiLineString(lines.release()));
-        //geom_ptr noded (segment->Union(mline.get()));
+        GeometryFactory gf;
+        geom_ptr mline = create_multi_line(gf, xnodes);
 
-        WKTWriter writer;
-        wkt->geom = writer.write(mline.get());
-        wkt->area = 0;
+        wkb.set(mline.get(), false);
     }//TODO: don't show in message id when osm_id == -1
     catch (const std::exception& e)
     {
-        std::cerr << std::endl << "Standard exception processing way_id="<< osm_id << ": " << e.what()  << std::endl;
+        std::cerr << std::endl << "Standard exception processing relation_id="<< osm_id << ": " << e.what()  << std::endl;
     }
     catch (...)
     {
-        std::cerr << std::endl << "Exception caught processing way id=" << osm_id << std::endl;
+        std::cerr << std::endl << "Exception caught processing relation id=" << osm_id << std::endl;
     }
-    return wkt;
+    return wkb;
 }
 
-geometry_builder::maybe_wkts_t geometry_builder::build_both(const multinodelist_t &xnodes,
+geometry_builder::pg_geoms_t geometry_builder::build_both(const multinodelist_t &xnodes,
                                                             int make_polygon, int enable_multi,
                                                             double split_at, osmid_t osm_id) const
 {
-    std::auto_ptr<std::vector<Geometry*> > lines(new std::vector<Geometry*>);
-    GeometryFactory gf;
-    geom_ptr geom;
-    geos::geom::prep::PreparedGeometryFactory pgf;
-    maybe_wkts_t wkts(new std::vector<geometry_builder::wkt_t>);
-
+    pg_geoms_t wkbs;
 
     try
     {
-        for (multinodelist_t::const_iterator it = xnodes.begin(); it != xnodes.end(); ++it) {
-            std::auto_ptr<CoordinateSequence> coords(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2));
-            for (nodelist_t::const_iterator node = it->begin(); node != it->end(); ++node) {
-                Coordinate c;
-                c.x = node->lon;
-                c.y = node->lat;
-                coords->add(c, 0);
-            }
-            if (coords->getSize() > 1) {
-                geom = geom_ptr(gf.createLineString(coords.release()));
-                lines->push_back(geom.release());
-            }
-        }
-
-        //geom_ptr segment(0);
-        geom_ptr mline (gf.createMultiLineString(lines.release()));
+        GeometryFactory gf;
+        geom_ptr mline = create_multi_line(gf, xnodes);
         //geom_ptr noded (segment->Union(mline.get()));
         LineMerger merger;
         //merger.add(noded.get());
         merger.add(mline.get());
-        std::auto_ptr<std::vector<LineString *> > merged(merger.getMergedLineStrings());
-        WKTWriter writer;
+        std::unique_ptr<std::vector<LineString *> > merged(merger.getMergedLineStrings());
 
         // Procces ways into lines or simple polygon list
-        std::vector<polygondata> polys(merged->size());
-
-        unsigned totalpolys = 0;
-        for (unsigned i=0 ;i < merged->size(); ++i)
-        {
-            std::auto_ptr<LineString> pline ((*merged ) [i]);
-            if (make_polygon && pline->getNumPoints() > 3 && pline->isClosed())
-            {
-                polys[totalpolys].polygon = gf.createPolygon(gf.createLinearRing(pline->getCoordinates()),0);
-                polys[totalpolys].ring = gf.createLinearRing(pline->getCoordinates());
-                polys[totalpolys].area = polys[totalpolys].polygon->getArea();
-                polys[totalpolys].iscontained = 0;
-                polys[totalpolys].containedbyid = 0;
-                if (polys[totalpolys].area > 0.0)
-                    totalpolys++;
-                else {
-                    delete(polys[totalpolys].polygon);
-                    delete(polys[totalpolys].ring);
+        std::vector<polygondata> polys;
+        polys.reserve(merged->size());
+
+        for (auto *line: *merged) {
+            // stuff into unique pointer to ensure auto-destruct
+            std::unique_ptr<LineString> pline(line);
+            if (make_polygon && pline->getNumPoints() > 3 && pline->isClosed()) {
+                std::unique_ptr<Polygon> poly(gf.createPolygon(gf.createLinearRing(pline->getCoordinates()),0));
+                double area = get_area(poly.get(), projection);
+                if (area > 0.0) {
+                    polys.emplace_back(std::move(poly),
+                                       gf.createLinearRing(pline->getCoordinates()),
+                                       area);
                 }
-            }
-            else
-            {
-                //std::cerr << "polygon(" << osm_id << ") is no good: points(" << pline->getNumPoints() << "), closed(" << pline->isClosed() << "). " << writer.write(pline.get()) << std::endl;
+            } else {
                 double distance = 0;
-                std::auto_ptr<CoordinateSequence> segment;
-                segment = std::auto_ptr<CoordinateSequence>(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2));
+                std::unique_ptr<CoordinateSequence> segment;
+                segment = std::unique_ptr<CoordinateSequence>(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2));
                 segment->add(pline->getCoordinateN(0));
-                for(unsigned i=1; i<pline->getNumPoints(); i++) {
-                    segment->add(pline->getCoordinateN(i));
-                    distance += pline->getCoordinateN(i).distance(pline->getCoordinateN(i-1));
-                    if ((distance >= split_at) || (i == pline->getNumPoints()-1)) {
+                for(int j=1; j<(int)pline->getNumPoints(); ++j) {
+                    segment->add(pline->getCoordinateN(j));
+                    distance += pline->getCoordinateN(j).distance(pline->getCoordinateN(j-1));
+                    if ((distance >= split_at) || (j == (int)pline->getNumPoints()-1)) {
                         geom_ptr geom = geom_ptr(gf.createLineString(segment.release()));
 
-                        //copy of an empty one should be cheapest
-                        wkts->push_back(geometry_builder::wkt_t());
-                        //then we set on the one we already have
-                        wkts->back().geom = writer.write(geom.get());
-                        wkts->back().area = 0;
+                        wkbs.emplace_back(geom.get(), false);
 
                         segment.reset(gf.getCoordinateSequenceFactory()->create((size_t)0, (size_t)2));
                         distance=0;
-                        segment->add(pline->getCoordinateN(i));
+                        segment->add(pline->getCoordinateN(j));
                     }
                 }
-                //std::string text = writer.write(pline.get());
-                //wkts.push_back(text);
-                //areas.push_back(0.0);
-                //wkt_size++;
             }
         }
 
-        if (totalpolys)
+        if (!polys.empty())
         {
-            std::sort(polys.begin(), polys.begin() + totalpolys, polygondata_comparearea());
+            std::sort(polys.begin(), polys.end(), polygondata_comparearea());
 
             unsigned toplevelpolygons = 0;
             int istoplevelafterall;
+            size_t totalpolys = polys.size();
 
+            geos::geom::prep::PreparedGeometryFactory pgf;
             for (unsigned i=0 ;i < totalpolys; ++i)
             {
-                if (polys[i].iscontained != 0) continue;
+                if (polys[i].iscontained) continue;
                 toplevelpolygons++;
-                const geos::geom::prep::PreparedGeometry* preparedtoplevelpolygon = pgf.create(polys[i].polygon);
+                const geos::geom::prep::PreparedGeometry* preparedtoplevelpolygon = pgf.create(polys[i].polygon.get());
 
                 for (unsigned j=i+1; j < totalpolys; ++j)
                 {
                     // Does preparedtoplevelpolygon contain the smaller polygon[j]?
-                    if (polys[j].containedbyid == 0 && preparedtoplevelpolygon->contains(polys[j].polygon))
+                    if (polys[j].containedbyid == 0 && preparedtoplevelpolygon->contains(polys[j].polygon.get()))
                     {
                         // are we in a [i] contains [k] contains [j] situation
                         // which would actually make j top level
                         istoplevelafterall = 0;
                         for (unsigned k=i+1; k < j; ++k)
                         {
-                            if (polys[k].iscontained && polys[k].containedbyid == i && polys[k].polygon->contains(polys[j].polygon))
+                            if (polys[k].iscontained && polys[k].containedbyid == i && polys[k].polygon->contains(polys[j].polygon.get()))
                             {
                                 istoplevelafterall = 1;
                                 break;
@@ -684,7 +651,7 @@ geometry_builder::maybe_wkts_t geometry_builder::build_both(const multinodelist_
                         }
                         if (istoplevelafterall == 0)
                         {
-                            polys[j].iscontained = 1;
+                            polys[j].iscontained = true;
                             polys[j].containedbyid = i;
                         }
                     }
@@ -694,24 +661,24 @@ geometry_builder::maybe_wkts_t geometry_builder::build_both(const multinodelist_
             // polys now is a list of polygons tagged with which ones are inside each other
 
             // List of polygons for multipolygon
-            std::auto_ptr<std::vector<Geometry*> > polygons(new std::vector<Geometry*>);
+            std::unique_ptr<std::vector<Geometry*> > polygons(new std::vector<Geometry*>);
 
             // For each top level polygon create a new polygon including any holes
             for (unsigned i=0 ;i < totalpolys; ++i)
             {
-                if (polys[i].iscontained != 0) continue;
+                if (polys[i].iscontained) continue;
 
                 // List of holes for this top level polygon
-                std::auto_ptr<std::vector<Geometry*> > interior(new std::vector<Geometry*>);
+                std::unique_ptr<std::vector<Geometry*> > interior(new std::vector<Geometry*>);
                 for (unsigned j=i+1; j < totalpolys; ++j)
                 {
-                   if (polys[j].iscontained == 1 && polys[j].containedbyid == i)
+                   if (polys[j].iscontained && polys[j].containedbyid == i)
                    {
-                       interior->push_back(polys[j].ring);
+                       interior->push_back(polys[j].ring.release());
                    }
                 }
 
-                Polygon* poly(gf.createPolygon(polys[i].ring, interior.release()));
+                Polygon* poly(gf.createPolygon(polys[i].ring.release(), interior.release()));
                 poly->normalize();
                 polygons->push_back(poly);
             }
@@ -720,46 +687,30 @@ geometry_builder::maybe_wkts_t geometry_builder::build_both(const multinodelist_
             if ((toplevelpolygons > 1) && enable_multi)
             {
                 geom_ptr multipoly(gf.createMultiPolygon(polygons.release()));
-                if (!multipoly->isValid() && (excludepoly == 0)) {
+                if (!multipoly->isValid() && !excludepoly) {
                     multipoly = geom_ptr(multipoly->buffer(0));
                 }
                 multipoly->normalize();
 
-                if ((excludepoly == 0) || (multipoly->isValid()))
-                {
-                    //copy of an empty one should be cheapest
-                    wkts->push_back(geometry_builder::wkt_t());
-                    //then we set on the one we already have
-                    wkts->back().geom = writer.write(multipoly.get());
-                    wkts->back().area = multipoly->getArea();
+                if ((excludepoly == 0) || (multipoly->isValid())) {
+                    wkbs.emplace_back(multipoly.get(), true, projection);
                 }
             }
             else
             {
                 for(unsigned i=0; i<toplevelpolygons; i++)
                 {
-                    Geometry* poly = dynamic_cast<Geometry*>(polygons->at(i));
-                    if (!poly->isValid() && (excludepoly == 0)) {
-                        poly = dynamic_cast<Geometry*>(poly->buffer(0));
+                    geom_ptr poly(polygons->at(i));
+                    if (!poly->isValid() && !excludepoly) {
+                        poly = geom_ptr(poly->buffer(0));
                         poly->normalize();
                     }
-                    if ((excludepoly == 0) || (poly->isValid()))
-                    {
-                        //copy of an empty one should be cheapest
-                        wkts->push_back(geometry_builder::wkt_t());
-                        //then we set on the one we already have
-                        wkts->back().geom = writer.write(poly);
-                        wkts->back().area = poly->getArea();
+                    if (!excludepoly || (poly->isValid())) {
+                        wkbs.emplace_back(poly.get(), true, projection);
                     }
-                    delete(poly);
                 }
             }
         }
-
-        for (unsigned i=0; i < totalpolys; ++i)
-        {
-            delete(polys[i].polygon);
-        }
     }//TODO: don't show in message id when osm_id == -1
     catch (const std::exception& e)
     {
@@ -770,17 +721,5 @@ geometry_builder::maybe_wkts_t geometry_builder::build_both(const multinodelist_
         std::cerr << std::endl << "Exception caught processing relation id=" << osm_id << std::endl;
     }
 
-    return wkts;
-}
-
-void geometry_builder::set_exclude_broken_polygon(int exclude)
-{
-    excludepoly = exclude;
-}
-
-geometry_builder::geometry_builder()
-    : excludepoly(0) {
-}
-
-geometry_builder::~geometry_builder() {
+    return wkbs;
 }
diff --git a/geometry-builder.hpp b/geometry-builder.hpp
index 4f8cac7..56457c1 100644
--- a/geometry-builder.hpp
+++ b/geometry-builder.hpp
@@ -27,40 +27,88 @@
 
 #include <vector>
 #include <string>
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
-struct geometry_builder : public boost::noncopyable
+namespace geos { namespace geom {
+class Geometry;
+class GeometryFactory;
+class CoordinateSequence;
+}}
+
+class reprojection;
+
+class geometry_builder
 {
-    struct wkt_t
+public:
+    struct pg_geom_t
     {
-        wkt_t(const std::string& geom, const double& area):geom(geom),area(area){}
-        wkt_t():geom(""),area(0){}
+        pg_geom_t(const std::string &geom_str, bool poly, double geom_area = 0)
+        : geom(geom_str), area(geom_area), polygon(poly)
+        {}
+
+        /// Create an invalid geometry.
+        pg_geom_t()
+        : area(0), polygon(false)
+        {}
+
+        pg_geom_t(const geos::geom::Geometry *g, bool poly, reprojection *p = nullptr)
+        {
+            set(g, poly, p);
+        }
+
+        /**
+         * Set geometry from a Geos geometry.
+         */
+        void set(const geos::geom::Geometry *geom, bool poly, reprojection *p = nullptr);
+
+
+        bool is_polygon() const
+        {
+            return polygon;
+        }
+
+        bool valid() const
+        {
+            return !geom.empty();
+        }
+
         std::string geom;
         double area;
+        bool polygon;
     };
 
-    // type to represent an optional return of WKT-encoded geometry
-    typedef boost::shared_ptr<geometry_builder::wkt_t> maybe_wkt_t;
-    typedef boost::shared_ptr<std::vector<geometry_builder::wkt_t> > maybe_wkts_t;
-    typedef std::vector<geometry_builder::wkt_t>::const_iterator wkt_itr;
-
-    geometry_builder();
-    ~geometry_builder();
+    typedef std::vector<geometry_builder::pg_geom_t> pg_geoms_t;
 
-    static int parse_wkt(const char *wkt, multinodelist_t &nodes, int *polygon);
-    maybe_wkt_t get_wkt_simple(const nodelist_t &nodes, int polygon) const;
-    maybe_wkts_t get_wkt_split(const nodelist_t &nodes, int polygon, double split_at) const;
-    maybe_wkts_t build_both(const multinodelist_t &xnodes, int make_polygon,
+    static int parse_wkb(const char *wkb, multinodelist_t &nodes, bool *polygon);
+    pg_geom_t get_wkb_simple(const nodelist_t &nodes, int polygon) const;
+    pg_geoms_t get_wkb_split(const nodelist_t &nodes, int polygon, double split_at) const;
+    pg_geoms_t build_both(const multinodelist_t &xnodes, int make_polygon,
                             int enable_multi, double split_at, osmid_t osm_id = -1) const;
-    maybe_wkts_t build_polygons(const multinodelist_t &xnodes, bool enable_multi, osmid_t osm_id = -1) const;
-    // Used by gazetteer. Outputting a multiline, it only ever returns one WKT
-    maybe_wkt_t build_multilines(const multinodelist_t &xnodes, osmid_t osm_id) const;
+    pg_geoms_t build_polygons(const multinodelist_t &xnodes, bool enable_multi, osmid_t osm_id = -1) const;
+    /** Output relation as a multiline.
+     *
+     *  Used by gazetteer only.
+     */
+    pg_geom_t build_multilines(const multinodelist_t &xnodes, osmid_t osm_id) const;
+
+    void set_exclude_broken_polygon(bool exclude)
+    {
+        excludepoly = exclude;
+    }
+
+    void set_reprojection(reprojection *r)
+    {
+        projection = r;
+    }
 
-    void set_exclude_broken_polygon(int exclude);
 
 private:
-    int excludepoly;
+    std::unique_ptr<geos::geom::Geometry>
+    create_simple_poly(geos::geom::GeometryFactory &gf,
+                       std::unique_ptr<geos::geom::CoordinateSequence> coords) const;
+
+    bool excludepoly = false;
+    reprojection *projection = nullptr;
 };
 
 #endif
diff --git a/geometry-processor.cpp b/geometry-processor.cpp
index 49f8b22..5b23eed 100644
--- a/geometry-processor.cpp
+++ b/geometry-processor.cpp
@@ -6,24 +6,24 @@
 #include "options.hpp"
 #include "reprojection.hpp"
 
-#include <boost/make_shared.hpp>
 #include <boost/format.hpp>
 #include <boost/optional.hpp>
 #include <stdexcept>
+#include <memory>
 
-boost::shared_ptr<geometry_processor> geometry_processor::create(const std::string &type,
+std::shared_ptr<geometry_processor> geometry_processor::create(const std::string &type,
                                                                  const options_t *options) {
-    boost::shared_ptr<geometry_processor> ptr;
-    int srid = options->projection->project_getprojinfo()->srs;
+    std::shared_ptr<geometry_processor> ptr;
+    int srid = options->projection->target_srs();
 
     if (type == "point") {
-        ptr = boost::make_shared<processor_point>(srid);
+        ptr = std::make_shared<processor_point>(srid);
     }
     else if (type == "line") {
-        ptr = boost::make_shared<processor_line>(srid);
+        ptr = std::make_shared<processor_line>(srid);
     }
     else if (type == "polygon") {
-        ptr = boost::make_shared<processor_polygon>(srid, options->enable_multi);
+        ptr = std::make_shared<processor_polygon>(srid, options->enable_multi);
     }
     else {
         throw std::runtime_error((boost::format("Unable to construct geometry processor "
@@ -57,16 +57,16 @@ bool geometry_processor::interests(unsigned int interested) const {
     return (interested & m_interests) == interested;
 }
 
-geometry_builder::maybe_wkt_t geometry_processor::process_node(double lat, double lon) {
-    return geometry_builder::maybe_wkt_t();
+geometry_builder::pg_geom_t geometry_processor::process_node(double, double) {
+    return geometry_builder::pg_geom_t();
 }
 
-geometry_builder::maybe_wkt_t geometry_processor::process_way(const nodelist_t &nodes) {
-    return geometry_builder::maybe_wkt_t();
+geometry_builder::pg_geom_t geometry_processor::process_way(const nodelist_t &) {
+    return geometry_builder::pg_geom_t();
 }
 
-geometry_builder::maybe_wkts_t geometry_processor::process_relation(const multinodelist_t &nodes) {
-    return geometry_builder::maybe_wkts_t();
+geometry_builder::pg_geoms_t geometry_processor::process_relation(const multinodelist_t &) {
+    return geometry_builder::pg_geoms_t();
 }
 
 way_helper::way_helper()
diff --git a/geometry-processor.hpp b/geometry-processor.hpp
index 336553c..83849fa 100644
--- a/geometry-processor.hpp
+++ b/geometry-processor.hpp
@@ -4,7 +4,7 @@
 #include <cstddef>
 #include <string>
 #include <vector>
-#include <boost/shared_ptr.hpp>
+#include <memory>
 #include "geometry-builder.hpp"
 #include "osmtypes.hpp"
 
@@ -14,7 +14,7 @@ struct options_t;
 
 struct geometry_processor {
     // factory method for creating various types of geometry processors either by name or by geometry column type
-    static boost::shared_ptr<geometry_processor> create(const std::string &type,
+    static std::shared_ptr<geometry_processor> create(const std::string &type,
                                                         const options_t *options);
 
     virtual ~geometry_processor();
@@ -38,19 +38,19 @@ struct geometry_processor {
     // LINESTRING, etc...) that this processor outputs
     const std::string &column_type() const;
 
-    // process a node, optionally returning a WKT string describing
+    // process a node, optionally returning a WKB string describing
     // geometry to be inserted into the table.
-    virtual geometry_builder::maybe_wkt_t process_node(double lat, double lon);
+    virtual geometry_builder::pg_geom_t process_node(double lat, double lon);
 
     // process a way
-    // position data and optionally returning WKT-encoded geometry
+    // position data and optionally returning WKB-encoded geometry
     // for insertion into the table.
-    virtual geometry_builder::maybe_wkt_t process_way(const nodelist_t &nodes);
+    virtual geometry_builder::pg_geom_t process_way(const nodelist_t &nodes);
 
     // process a way, taking a middle query object to get way and
-    // node position data. optionally returns a WKT-encoded geometry
+    // node position data. optionally returns an array of WKB-encoded geometry
     // for insertion into the table.
-    virtual geometry_builder::maybe_wkts_t process_relation(const multinodelist_t &nodes);
+    virtual geometry_builder::pg_geoms_t process_relation(const multinodelist_t &nodes);
 
     // returns the SRID of the output geometry.
     int srid() const;
diff --git a/geos-fallback/geos/noding/SegmentNode.h b/geos-fallback/geos/noding/SegmentNode.h
deleted file mode 100644
index 9a43bed..0000000
--- a/geos-fallback/geos/noding/SegmentNode.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/**********************************************************************
- * $Id: SegmentNode.h 1820 2006-09-06 16:54:23Z mloskot $
- *
- * GEOS - Geometry Engine Open Source
- * http://geos.refractions.net
- *
- * Copyright (C) 2006      Refractions Research Inc.
- *
- * This is free software; you can redistribute and/or modify it under
- * the terms of the GNU Lesser General Public Licence as published
- * by the Free Software Foundation. 
- * See the COPYING file for more information.
- *
- **********************************************************************/
-
-#ifndef GEOS_NODING_SEGMENTNODE_H
-#define GEOS_NODING_SEGMENTNODE_H
-
-#include <vector>
-#include <iostream>
-
-#include <geos/inline.h>
-
-#include <geos/geom/Coordinate.h>
-
-// Forward declarations
-namespace geos {
-	namespace noding {
-		class SegmentString;
-	}
-}
-
-namespace geos {
-namespace noding { // geos.noding
-
-/// Represents an intersection point between two SegmentString.
-//
-/// Final class.
-///
-/// Last port: noding/SegmentNode.java rev. 1.5 (JTS-1.7)
-///
-class SegmentNode {
-private:
-	const SegmentString& segString;
-
-	int segmentOctant;
-
-	bool isInteriorVar;
-
-public:
-	friend std::ostream& operator<< (std::ostream& os, const SegmentNode& n);
-
-	/// the point of intersection (own copy)
-	geom::Coordinate coord;  
-
-	/// the index of the containing line segment in the parent edge
-	unsigned int segmentIndex;  
-
-	/// Construct a node on the given SegmentString
-	//
-	/// @param ss the parent SegmentString 
-	///
-	/// @param coord the coordinate of the intersection, will be copied
-	///
-	/// @param nSegmentIndex the index of the segment on parent SegmentString
-	///        where the Node is located.
-	///
-	/// @param nSegmentOctant
-	///
-	SegmentNode(const SegmentString& ss, const geom::Coordinate& nCoord,
-			unsigned int nSegmentIndex, int nSegmentOctant);
-
-	~SegmentNode() {}
-
-	/// \brief
-	/// Return true if this Node is *internal* (not on the boundary)
-	/// of the corresponding segment. Currently only the *first*
-	/// segment endpoint is checked, actually.
-	///
-	bool isInterior() const { return isInteriorVar; }
-
-	bool isEndPoint(unsigned int maxSegmentIndex) const;
-
-	/**
-	 * @return -1 this EdgeIntersection is located before
-	 *            the argument location
-	 * @return 0 this EdgeIntersection is at the argument location
-	 * @return 1 this EdgeIntersection is located after the
-	 *           argument location
-	 */
-	int compareTo(const SegmentNode& other);
-
-	//string print() const;
-};
-
-std::ostream& operator<< (std::ostream& os, const SegmentNode& n);
-
-struct SegmentNodeLT {
-	bool operator()(SegmentNode *s1, SegmentNode *s2) const {
-		return s1->compareTo(*s2)<0;
-	}
-};
-
-
-} // namespace geos.noding
-} // namespace geos
-
-//#ifdef GEOS_INLINE
-//# include "geos/noding/SegmentNode.inl"
-//#endif
-
-#endif // GEOS_NODING_SEGMENTNODE_H
-
-/**********************************************************************
- * $Log$
- * Revision 1.2  2006/03/24 09:52:41  strk
- * USE_INLINE => GEOS_INLINE
- *
- * Revision 1.1  2006/03/09 16:46:49  strk
- * geos::geom namespace definition, first pass at headers split
- *
- **********************************************************************/
-
diff --git a/geos-fallback/geos/noding/SegmentNodeList.h b/geos-fallback/geos/noding/SegmentNodeList.h
deleted file mode 100644
index 8c22a65..0000000
--- a/geos-fallback/geos/noding/SegmentNodeList.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/**********************************************************************
- * $Id: SegmentNodeList.h 1820 2006-09-06 16:54:23Z mloskot $
- *
- * GEOS - Geometry Engine Open Source
- * http://geos.refractions.net
- *
- * Copyright (C) 2006      Refractions Research Inc.
- *
- * This is free software; you can redistribute and/or modify it under
- * the terms of the GNU Lesser General Public Licence as published
- * by the Free Software Foundation. 
- * See the COPYING file for more information.
- *
- **********************************************************************/
-
-#ifndef GEOS_NODING_SEGMENTNODELIST_H
-#define GEOS_NODING_SEGMENTNODELIST_H
-
-#include <geos/inline.h>
-
-#include <cassert>
-#include <iostream>
-#include <vector>
-#include <set>
-
-#include <geos/noding/SegmentNode.h>
-
-// Forward declarations
-namespace geos {
-	namespace geom {
-		class CoordinateSequence;
-	}
-	namespace noding {
-		class SegmentString;
-	}
-}
-
-namespace geos {
-namespace noding { // geos::noding
-
-/** \brief
- * A list of the SegmentNode present along a
- * noded SegmentString.
- *
- * Last port: noding/SegmentNodeList.java rev. 1.7 (JTS-1.7)
- */
-class SegmentNodeList {
-private:
-	std::set<SegmentNode*,SegmentNodeLT> nodeMap;
-
-	// the parent edge
-	const SegmentString& edge; 
-
-	// UNUSED
-	//std::vector<SegmentNode*> *sortedNodes;
-
-	// This vector is here to keep track of created splitEdges
-	std::vector<SegmentString*> splitEdges;
-
-	// This vector is here to keep track of created Coordinates
-	std::vector<geom::CoordinateSequence*> splitCoordLists;
-
-	/**
-	 * Checks the correctness of the set of split edges corresponding
-	 * to this edge
-	 *
-	 * @param splitEdges the split edges for this edge (in order)
-	 */
-	void checkSplitEdgesCorrectness(std::vector<SegmentString*>& splitEdges);
-
-	/**
-	 * Create a new "split edge" with the section of points between
-	 * (and including) the two intersections.
-	 * The label for the new edge is the same as the label for the
-	 * parent edge.
-	 */
-	SegmentString* createSplitEdge(SegmentNode *ei0, SegmentNode *ei1);
-
-	/**
-	 * Adds nodes for any collapsed edge pairs.
-	 * Collapsed edge pairs can be caused by inserted nodes, or they
-	 * can be pre-existing in the edge vertex list.
-	 * In order to provide the correct fully noded semantics,
-	 * the vertex at the base of a collapsed pair must also be added
-	 * as a node.
-	 */
-	void addCollapsedNodes();
-
-	/**
-	 * Adds nodes for any collapsed edge pairs
-	 * which are pre-existing in the vertex list.
-	 */
-	void findCollapsesFromExistingVertices(
-			std::vector<size_t>& collapsedVertexIndexes);
-
-	/**
-	 * Adds nodes for any collapsed edge pairs caused by inserted nodes
-	 * Collapsed edge pairs occur when the same coordinate is inserted
-	 * as a node both before and after an existing edge vertex.
-	 * To provide the correct fully noded semantics,
-	 * the vertex must be added as a node as well.
-	 */
-	void findCollapsesFromInsertedNodes(
-		std::vector<size_t>& collapsedVertexIndexes);
-
-	bool findCollapseIndex(SegmentNode& ei0, SegmentNode& ei1,
-		size_t& collapsedVertexIndex);
-public:
-
-	friend std::ostream& operator<< (std::ostream& os, const SegmentNodeList& l);
-
-	typedef std::set<SegmentNode*,SegmentNodeLT> container;
-	typedef container::iterator iterator;
-	typedef container::const_iterator const_iterator;
-
-	SegmentNodeList(const SegmentString* newEdge): edge(*newEdge) {}
-
-	SegmentNodeList(const SegmentString& newEdge): edge(newEdge) {}
-
-	const SegmentString& getEdge() const { return edge; }
-
-	// TODO: Is this a final class ?
-	// Should remove the virtual in that case
-	virtual ~SegmentNodeList();
-
-	/**
-	 * Adds an intersection into the list, if it isn't already there.
-	 * The input segmentIndex is expected to be normalized.
-	 *
-	 * @return the SegmentIntersection found or added. It will be
-	 *	   destroyed at SegmentNodeList destruction time.
-	 *
-	 * @param intPt the intersection Coordinate, will be copied
-	 * @param segmentIndex 
-	 */
-	SegmentNode* add(const geom::Coordinate& intPt, size_t segmentIndex);
-
-	SegmentNode* add(const geom::Coordinate *intPt, size_t segmentIndex) {
-		return add(*intPt, segmentIndex);
-	}
-
-	/*
-	 * returns the set of SegmentNodes
-	 */
-	//replaces iterator()
-	// TODO: obsolete this function
-	std::set<SegmentNode*,SegmentNodeLT>* getNodes() { return &nodeMap; }
-
-	/// Return the number of nodes in this list
-	size_t size() const { return nodeMap.size(); }
-
-	container::iterator begin() { return nodeMap.begin(); }
-	container::const_iterator begin() const { return nodeMap.begin(); }
-	container::iterator end() { return nodeMap.end(); }
-	container::const_iterator end() const { return nodeMap.end(); }
-
-	/**
-	 * Adds entries for the first and last points of the edge to the list
-	 */
-	void addEndpoints();
-
-	/**
-	 * Creates new edges for all the edges that the intersections in this
-	 * list split the parent edge into.
-	 * Adds the edges to the input list (this is so a single list
-	 * can be used to accumulate all split edges for a Geometry).
-	 */
-	void addSplitEdges(std::vector<SegmentString*>& edgeList);
-
-	void addSplitEdges(std::vector<SegmentString*>* edgeList) {
-		assert(edgeList);
-		addSplitEdges(*edgeList);
-	}
-
-	//string print();
-};
-
-std::ostream& operator<< (std::ostream& os, const SegmentNodeList& l);
-
-} // namespace geos::noding
-} // namespace geos
-
-//#ifdef GEOS_INLINE
-//# include "geos/noding/SegmentNodeList.inl"
-//#endif
-
-#endif
-
-/**********************************************************************
- * $Log$
- * Revision 1.4  2006/06/12 11:29:23  strk
- * unsigned int => size_t
- *
- * Revision 1.3  2006/05/04 07:41:56  strk
- * const-correct size() method for SegmentNodeList
- *
- * Revision 1.2  2006/03/24 09:52:41  strk
- * USE_INLINE => GEOS_INLINE
- *
- * Revision 1.1  2006/03/09 16:46:49  strk
- * geos::geom namespace definition, first pass at headers split
- *
- **********************************************************************/
-
diff --git a/geos-fallback/geos/noding/SegmentString.h b/geos-fallback/geos/noding/SegmentString.h
deleted file mode 100644
index 7e36896..0000000
--- a/geos-fallback/geos/noding/SegmentString.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/**********************************************************************
- * $Id: SegmentString.h 1872 2006-10-20 11:18:39Z strk $
- *
- * GEOS - Geometry Engine Open Source
- * http://geos.refractions.net
- *
- * Copyright (C) 2006      Refractions Research Inc.
- *
- * This is free software; you can redistribute and/or modify it under
- * the terms of the GNU Lesser General Public Licence as published
- * by the Free Software Foundation. 
- * See the COPYING file for more information.
- *
- **********************************************************************/
-
-#ifndef GEOS_NODING_SEGMENTSTRING_H
-#define GEOS_NODING_SEGMENTSTRING_H
-
-#include <geos/noding/SegmentNodeList.h>
-#include <geos/geom/CoordinateSequence.h> // for testInvariant
-
-#include <geos/inline.h>
-
-#include <vector>
-
-// Forward declarations
-namespace geos {
-	namespace algorithm {
-		class LineIntersector;
-	}
-}
-
-namespace geos {
-namespace noding { // geos.noding
-
-/** \brief
- * Represents a list of contiguous line segments,
- * and supports noding the segments.
- *
- * The line segments are represented by a CoordinateSequence.
- *
- * TODO:
- * This should be changed to use a vector of Coordinate,
- * to optimize the noding of contiguous segments by
- * reducing the number of allocated objects.
- *
- * SegmentStrings can carry a context object, which is useful
- * for preserving topological or parentage information.
- * All noded substrings are initialized with the same context object.
- *
- * Final class.
- *
- * Last port: noding/SegmentString.java rev. 1.5 (JTS-1.7)
- */
-class SegmentString {
-public:
-	typedef std::vector<const SegmentString*> ConstVect;
-	typedef std::vector<SegmentString *> NonConstVect;
-
-	friend std::ostream& operator<< (std::ostream& os,
-			const SegmentString& ss);
-
-private:
-	SegmentNodeList nodeList;
-	geom::CoordinateSequence *pts;
-	mutable unsigned int npts; // this is a cache
-	const void* context;
-	bool isIsolatedVar;
-
-public:
-
-	void testInvariant() const;
-
-	/// Construct a SegmentString.
-	//
-	/// @param newPts CoordinateSequence representing the string,
-	/// externally owned
-	///
-	/// @param newContext the context associated to this SegmentString
-	///
-	SegmentString(geom::CoordinateSequence *newPts, const void* newContext);
-
-	~SegmentString();
-
-	//const void* getContext() const { return getData(); }
-
-	const void* getData() const;
-
-	const SegmentNodeList& getNodeList() const;
-
-	SegmentNodeList& getNodeList();
-
-	unsigned int size() const;
-
-	const geom::Coordinate& getCoordinate(unsigned int i) const;
-
-	/// \brief
-	/// Return a pointer to the CoordinateSequence associated
-	/// with this SegmentString.
-	//
-	/// Note that the CoordinateSequence is not owned by
-	/// this SegmentString!
-	///
-	geom::CoordinateSequence* getCoordinates() const;
-
-	/// \brief
-	/// Notify this object that the CoordinateSequence associated
-	/// with it might have been updated.
-	//
-	/// This must be called so that the SegmentString object makes
-	/// all the necessary checks and updates to verify consistency
-	///
-	void notifyCoordinatesChange() const;
-
-	// Return a read-only pointer to this SegmentString CoordinateSequence
-	//const CoordinateSequence* getCoordinatesRO() const { return pts; }
-
-	void setIsolated(bool isIsolated);
-
-	bool isIsolated() const;
-	
-	bool isClosed() const;
-
-	/** \brief
-	 * Gets the octant of the segment starting at vertex
-	 * <code>index</code>.
-	 *
-	 * @param index the index of the vertex starting the segment. 
-	 *              Must not be the last index in the vertex list
-	 * @return the octant of the segment at the vertex
-	 */
-	int getSegmentOctant(unsigned int index) const;
-
-	/** \brief
-	 * Add {SegmentNode}s for one or both
-	 * intersections found for a segment of an edge to the edge
-	 * intersection list.
-	 */
-	void addIntersections(algorithm::LineIntersector *li,
-			unsigned int segmentIndex, int geomIndex);
-
-	/** \brief
-	 * Add an SegmentNode for intersection intIndex.
-	 *
-	 * An intersection that falls exactly on a vertex
-	 * of the SegmentString is normalized
-	 * to use the higher of the two possible segmentIndexes
-	 */
-	void addIntersection(algorithm::LineIntersector *li,
-			unsigned int segmentIndex,
-			int geomIndex, int intIndex);
-
-	/** \brief
-	 * Add an SegmentNode for intersection intIndex.
-	 *
-	 * An intersection that falls exactly on a vertex of the
-	 * edge is normalized
-	 * to use the higher of the two possible segmentIndexes
-	 */
-	void addIntersection(const geom::Coordinate& intPt,
-			unsigned int segmentIndex);
-
-	static void getNodedSubstrings(
-			const SegmentString::NonConstVect& segStrings,
-			SegmentString::NonConstVect* resultEdgeList);
-
-	static SegmentString::NonConstVect* getNodedSubstrings(
-			const SegmentString::NonConstVect& segStrings);
-};
-
-inline void
-SegmentString::testInvariant() const
-{
-	assert(pts);
-	assert(pts->size() > 1);
-	assert(pts->size() == npts);
-}
-
-std::ostream& operator<< (std::ostream& os, const SegmentString& ss);
-
-} // namespace geos.noding
-} // namespace geos
-
-#ifdef GEOS_INLINE
-# include "geos/noding/SegmentString.inl"
-#endif
-
-#endif
-
-/**********************************************************************
- * $Log$
- * Revision 1.10  2006/05/05 14:25:05  strk
- * moved getSegmentOctant out of .inl into .cpp, renamed private eiList to nodeList as in JTS, added more assertion checking and fixed doxygen comments
- *
- * Revision 1.9  2006/05/05 10:19:06  strk
- * droppped SegmentString::getContext(), new name is getData() to reflect change in JTS
- *
- * Revision 1.8  2006/05/04 08:29:07  strk
- * * source/noding/ScaledNoder.cpp: removed use of SegmentString::setCoordinates().
- * * source/headers/geos/noding/SegmentStrign.{h,inl}: removed new setCoordinates() interface.
- *
- * Revision 1.7  2006/05/04 07:43:44  strk
- * output operator for SegmentString class
- *
- * Revision 1.6  2006/05/03 18:04:49  strk
- * added SegmentString::setCoordinates() interface
- *
- * Revision 1.5  2006/05/03 16:19:39  strk
- * fit in 80 columns
- *
- * Revision 1.4  2006/05/03 15:26:02  strk
- * testInvariant made public and always inlined
- *
- * Revision 1.3  2006/03/24 09:52:41  strk
- * USE_INLINE => GEOS_INLINE
- *
- * Revision 1.2  2006/03/13 21:14:24  strk
- * Added missing forward declarations
- *
- * Revision 1.1  2006/03/09 16:46:49  strk
- * geos::geom namespace definition, first pass at headers split
- *
- **********************************************************************/
-
diff --git a/id-tracker.hpp b/id-tracker.hpp
index 7135316..f76ffc6 100644
--- a/id-tracker.hpp
+++ b/id-tracker.hpp
@@ -3,14 +3,31 @@
 
 #include "osmtypes.hpp"
 #include <boost/noncopyable.hpp>
-#include <boost/scoped_ptr.hpp>
+#include <memory>
 
+/**
+  * Tracker for if an element needs to be revisited later in the process, also
+  * known as "pending". This information used to be stored in the database, but
+  * is ephemeral and lead to database churn, bloat, and was generally slow.
+  * An initial re-implementation stored it as a std::set<osmid_t>, which worked
+  * but was inefficient with memory overhead and pointer chasing.
+  *
+  * Instead, the size of the leaf nodes is increased. This was initially a
+  * vector<bool>, but the cost of exposing the iterator was too high.
+  * Instead, it's a uint32, with a function to find the next bit set in the block
+  *
+  * These details aren't exposed in the public interface, which just has
+  * pop_mark.
+  */
 struct id_tracker : public boost::noncopyable {
     id_tracker();
     ~id_tracker();
 
     void mark(osmid_t id);
     bool is_marked(osmid_t id);
+    /**
+     * Finds an osmid_t that is marked
+     */
     osmid_t pop_mark();
     size_t size();
     osmid_t last_returned() const;
@@ -21,7 +38,7 @@ struct id_tracker : public boost::noncopyable {
 
 private:
     struct pimpl;
-    boost::scoped_ptr<pimpl> impl;
+    std::unique_ptr<pimpl> impl;
 };
 
 #endif /* ID_TRACKER_HPP */
diff --git a/input.cpp b/input.cpp
deleted file mode 100644
index a56c45b..0000000
--- a/input.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-#define _FILE_OFFSET_BITS 64
-#define _LARGEFILE64_SOURCE
-
-#ifdef _WIN32
-#include <windows.h>
-#include <io.h>
-#define STDIN_FILENO 0
-#else
-#include <cstdio>
-#endif
-
-#include <cstdlib>
-#include <cstring>
-#include <fcntl.h>
-#include <zlib.h>
-#include <bzlib.h>
-
-#include "input.hpp"
-
-struct Input {
-  char *name;
-  enum { plainFile, gzipFile, bzip2File } type;
-  void *fileHandle;
-    /* needed by bzip2 when decompressing from multiple streams. other
-       decompressors must ignore it. */
-  FILE *systemHandle;
-  int eof;
-  char buf[4096];
-  int buf_ptr, buf_fill;
-};
-
-/* tries to re-open the bz stream at the next stream start.
-   returns 0 on success, -1 on failure. */
-int bzReOpen(struct Input *ctx, int *error) {
-    /* for copying out the last unused part of the block which
-       has an EOS token in it. needed for re-initialising the
-       next stream. */
-  unsigned char unused[BZ_MAX_UNUSED];
-  void *unused_tmp_ptr = NULL;
-  int nUnused, i;
-
-  BZ2_bzReadGetUnused(error, (BZFILE *)(ctx->fileHandle), &unused_tmp_ptr, &nUnused);
-  if (*error != BZ_OK) return -1;
-
-  /* when bzReadClose is called the unused buffer is deallocated,
-     so it needs to be copied somewhere safe first. */
-  for (i = 0; i < nUnused; ++i)
-    unused[i] = ((unsigned char *)unused_tmp_ptr)[i];
-
-  BZ2_bzReadClose(error, (BZFILE *)(ctx->fileHandle));
-  if (*error != BZ_OK) return -1;
-
-  /* reassign the file handle */
-  ctx->fileHandle = BZ2_bzReadOpen(error, ctx->systemHandle, 0, 0, unused, nUnused);
-  if (ctx->fileHandle == NULL || *error != BZ_OK) return -1;
-
-  return 0;
-}
-
-int readFile(struct Input *ctx, char * buffer, int len)
-{
-    void *f = ctx->fileHandle;
-    int l = 0, error = 0;
-
-    if (ctx->eof || (len == 0))
-        return 0;
-
-    switch(ctx->type) {
-    case Input::plainFile:
-        l = read(*(int *)f, buffer, len);
-        if (l <= 0) ctx->eof = 1;
-        break;
-    case Input::gzipFile:
-        l = gzread((gzFile)f, buffer, len);
-        if (l <= 0) ctx->eof = 1;
-        break;
-    case Input::bzip2File:
-        l = BZ2_bzRead(&error, (BZFILE *)f, buffer, len);
-
-        /* error codes BZ_OK and BZ_STREAM_END are both "OK", but the stream
-           end means the reader needs to be reset from the original handle. */
-        if (error != BZ_OK) {
-            /* for stream errors, try re-opening the stream before admitting defeat. */
-	    if (error != BZ_STREAM_END || bzReOpen(ctx, &error) != 0) {
-                l = 0;
-                ctx->eof = 1;
-	    }
-        }
-        break;
-    default:
-        fprintf(stderr, "Bad file type\n");
-        break;
-    }
-
-    if (l < 0) {
-      fprintf(stderr, "File reader received error %d (%d)\n", l, error);
-        l = 0;
-    }
-
-    return l;
-}
-
-char inputGetChar(struct Input *ctx)
-{
-    if (ctx->buf_ptr == ctx->buf_fill) {
-        ctx->buf_fill = readFile(ctx, &ctx->buf[0], sizeof(ctx->buf));
-        ctx->buf_ptr = 0;
-        if (ctx->buf_fill == 0)
-            return 0;
-        if (ctx->buf_fill < 0) {
-            perror("Error while reading file");
-            exit(1);
-        }
-    }
-    return ctx->buf[ctx->buf_ptr++];
-}
-
-int inputEof(struct Input *ctx)
-{
-    return ctx->eof;
-}
-
-
-struct Input *inputOpen(const char *name)
-{
-    const char *ext = strrchr(name, '.');
-    struct Input *ctx = (struct Input *)malloc(sizeof(*ctx));
-
-    if (!ctx)
-        return NULL;
-
-    memset(ctx, 0, sizeof(*ctx));
-
-    ctx->name = (char *)malloc(strlen(name) + 1);
-    if (ctx->name) strcpy(ctx->name, name);
-
-    if (ext && !strcmp(ext, ".gz")) {
-        ctx->fileHandle = (void *)gzopen(name, "rb");
-        ctx->type = Input::gzipFile;
-    } else if (ext && !strcmp(ext, ".bz2")) {
-      int error = 0;
-      ctx->systemHandle = fopen(name, "rb");
-      if (!ctx->systemHandle) {
-        fprintf(stderr, "error while opening file %s\n", name);
-        exit(10);
-      }
-
-      ctx->fileHandle = (void *)BZ2_bzReadOpen(&error, ctx->systemHandle, 0, 0, NULL, 0);
-      ctx->type = Input::bzip2File;
-
-    } else {
-        int *pfd = (int *)malloc(sizeof(int));
-        if (pfd) {
-            if (!strcmp(name, "-")) {
-                *pfd = STDIN_FILENO;
-            } else {
-                int flags = O_RDONLY;
-#ifdef O_LARGEFILE
-                flags |= O_LARGEFILE;
-#endif
-                *pfd = open(name, flags);
-                if (*pfd < 0) {
-                    free(pfd);
-                    pfd = NULL;
-                }
-            }
-        }
-        ctx->fileHandle = (void *)pfd;
-        ctx->type = Input::plainFile;
-    }
-    if (!ctx->fileHandle) {
-        fprintf(stderr, "error while opening file %s\n", name);
-        exit(10);
-    }
-    ctx->buf_ptr = 0;
-    ctx->buf_fill = 0;
-    return ctx;
-}
-
-int inputClose(struct Input *ctx)
-{
-    void *f = ctx->fileHandle;
-
-    switch(ctx->type) {
-    case Input::plainFile:
-        close(*(int *)f);
-        free(f);
-        break;
-    case Input::gzipFile:
-        gzclose((gzFile)f);
-        break;
-    case Input::bzip2File:
-        BZ2_bzclose((BZFILE *)f);
-        break;
-    default:
-        fprintf(stderr, "Bad file type\n");
-        break;
-    }
-
-    free(ctx->name);
-    free(ctx);
-    return 0;
-}
-
-// NOTE: need the two function variants below to fit into what
-// libXML expects the function signatures to be.
-
-static int readFileXML(void *context, char *buffer, int len) {
-    return readFile((struct Input *)context, buffer, len);
-}
-
-static int inputCloseXML(void *context) {
-    return inputClose((struct Input *)context);
-}
-
-xmlTextReaderPtr inputUTF8(const char *name)
-{
-    void *ctx = inputOpen(name);
-
-    if (!ctx) {
-        fprintf(stderr, "Input reader create failed for: %s\n", name);
-        return NULL;
-    }
-
-    return xmlReaderForIO(readFileXML, inputCloseXML, (void *)ctx, NULL, NULL, 0);
-}
diff --git a/input.hpp b/input.hpp
deleted file mode 100644
index 61213b2..0000000
--- a/input.hpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef INPUT_H
-#define INPUT_H
-
-#include <libxml/xmlreader.h>
-struct Input;
-
-int readFile(struct Input *context, char * buffer, int len);
-int inputClose(struct Input *context);
-struct Input *inputOpen(const char *name);
-char inputGetChar(struct Input *context);
-int inputEof(struct Input *context);
-xmlTextReaderPtr inputUTF8(const char *name);
-
-#endif
diff --git a/install-postgis-osm-db.sh b/install-postgis-osm-db.sh
index 34e16f8..88e1cad 100755
--- a/install-postgis-osm-db.sh
+++ b/install-postgis-osm-db.sh
@@ -30,27 +30,27 @@ fi
         echo "Initializing Spatial Extentions for postgresql 9.1"
         file_postgis=/usr/share/postgresql/9.1/contrib/postgis-1.5/postgis.sql
         file_spatial_ref=/usr/share/postgresql/9.1/contrib/postgis-1.5/spatial_ref_sys.sql
-        
+
         sudo -u postgres psql $DBNAME <$file_postgis >/dev/null 2>&1
         sudo -u postgres psql $DBNAME <$file_spatial_ref >/dev/null 2>&1
         echo "Spatial Extentions initialized"
-        
+
         echo "Initializing hstore"
         echo "CREATE EXTENSION hstore;" | sudo -u postgres psql $DBNAME
     else
         echo "Initializing Spatial Extentions for postgresql 8.4"
         file_postgis=/usr/share/postgresql/8.4/contrib/postgis-1.5/postgis.sql
         file_spatial_ref=/usr/share/postgresql/8.4/contrib/postgis-1.5/spatial_ref_sys.sql
-        
+
         sudo -u postgres psql $DBNAME <$file_postgis >/dev/null 2>&1
         sudo -u postgres psql $DBNAME <$file_spatial_ref >/dev/null 2>&1
         echo "Spatial Extentions initialized"
-        
+
         echo "Initializing hstore"
         file_hstore=/usr/share/postgresql/8.4/contrib/hstore.sql
         sudo -u postgres psql $DBNAME <$file_hstore >/dev/null 2>&1
     fi fi
-    
+
     echo "Setting ownership to user $DBOWNER"
 
     echo 'ALTER TABLE geometry_columns OWNER TO ' $DBOWNER '; ALTER TABLE spatial_ref_sys OWNER TO ' $DBOWNER ';' | sudo -u postgres psql $DBNAME
@@ -62,7 +62,7 @@ if [ -n "$GRANT_USER" ] ; then
     if [ "$GRANT_USER" = "*" ] ; then
 	echo "GRANT Rights to every USER"
 	GRANT_USER=''
-	for user in `users` ; do 
+	for user in `users` ; do
 	    GRANT_USER="$GRANT_USER $user"
 	done
     fi
diff --git a/install-postgis-osm-user.sh b/install-postgis-osm-user.sh
index 91c1da5..97bb56c 100755
--- a/install-postgis-osm-user.sh
+++ b/install-postgis-osm-user.sh
@@ -15,7 +15,7 @@ if [ -n "$GRANT_USER" ] ; then
     if [ "$GRANT_USER" = "*" ] ; then
 	echo "GRANT Rights to every USER"
 	GRANT_USER=''
-	for user in `users` ; do 
+	for user in `users` ; do
 	    GRANT_USER="$GRANT_USER $user"
 	done
     fi
diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4
deleted file mode 100644
index aeab899..0000000
--- a/m4/ax_append_flag.m4
+++ /dev/null
@@ -1,71 +0,0 @@
-# ===========================================================================
-#      http://www.gnu.org/software/autoconf-archive/ax_append_flag.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-#   AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE])
-#
-# DESCRIPTION
-#
-#   FLAG is appended to the FLAGS-VARIABLE shell variable, with a space
-#   added in between.
-#
-#   If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
-#   CFLAGS) is used.  FLAGS-VARIABLE is not changed if it already contains
-#   FLAG.  If FLAGS-VARIABLE is unset in the shell, it is set to exactly
-#   FLAG.
-#
-#   NOTE: Implementation based on AX_CFLAGS_GCC_OPTION.
-#
-# LICENSE
-#
-#   Copyright (c) 2008 Guido U. Draheim <guidod at gmx.de>
-#   Copyright (c) 2011 Maarten Bosmans <mkbosmans at gmail.com>
-#
-#   This program is free software: you can redistribute it and/or modify it
-#   under the terms of the GNU General Public License as published by the
-#   Free Software Foundation, either version 3 of the License, or (at your
-#   option) any later version.
-#
-#   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 for more details.
-#
-#   You should have received a copy of the GNU General Public License along
-#   with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-#   As a special exception, the respective Autoconf Macro's copyright owner
-#   gives unlimited permission to copy, distribute and modify the configure
-#   scripts that are the output of Autoconf when processing the Macro. You
-#   need not follow the terms of the GNU General Public License when using
-#   or distributing such scripts, even though portions of the text of the
-#   Macro appear in them. The GNU General Public License (GPL) does govern
-#   all other use of the material that constitutes the Autoconf Macro.
-#
-#   This special exception to the GPL applies to versions of the Autoconf
-#   Macro released by the Autoconf Archive. When you make and distribute a
-#   modified version of the Autoconf Macro, you may extend this special
-#   exception to the GPL to apply to your modified version as well.
-
-#serial 5
-
-AC_DEFUN([AX_APPEND_FLAG],
-[dnl
-AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
-AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
-AS_VAR_SET_IF(FLAGS,[
-  AS_CASE([" AS_VAR_GET(FLAGS) "],
-    [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
-    [
-     AS_VAR_APPEND(FLAGS," $1")
-     AC_RUN_LOG([: FLAGS="$FLAGS"])
-    ])
-  ],
-  [
-  AS_VAR_SET(FLAGS,[$1])
-  AC_RUN_LOG([: FLAGS="$FLAGS"])
-  ])
-AS_VAR_POPDEF([FLAGS])dnl
-])dnl AX_APPEND_FLAG
diff --git a/m4/ax_boost_base.m4 b/m4/ax_boost_base.m4
deleted file mode 100644
index f3279f2..0000000
--- a/m4/ax_boost_base.m4
+++ /dev/null
@@ -1,285 +0,0 @@
-# ===========================================================================
-#       http://www.gnu.org/software/autoconf-archive/ax_boost_base.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-#   AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-#
-# DESCRIPTION
-#
-#   Test for the Boost C++ libraries of a particular version (or newer)
-#
-#   If no path to the installed boost library is given the macro searchs
-#   under /usr, /usr/local, /opt and /opt/local and evaluates the
-#   $BOOST_ROOT environment variable. Further documentation is available at
-#   <http://randspringer.de/boost/index.html>.
-#
-#   This macro calls:
-#
-#     AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS)
-#
-#   And sets:
-#
-#     HAVE_BOOST
-#
-# LICENSE
-#
-#   Copyright (c) 2008 Thomas Porschberg <thomas at randspringer.de>
-#   Copyright (c) 2009 Peter Adolphs
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved. This file is offered as-is, without any
-#   warranty.
-
-#serial 26
-
-AC_DEFUN([AX_BOOST_BASE],
-[
-AC_ARG_WITH([boost],
-  [AS_HELP_STRING([--with-boost@<:@=ARG@:>@],
-    [use Boost library from a standard location (ARG=yes),
-     from the specified location (ARG=<path>),
-     or disable it (ARG=no)
-     @<:@ARG=yes@:>@ ])],
-    [
-    if test "$withval" = "no"; then
-        want_boost="no"
-    elif test "$withval" = "yes"; then
-        want_boost="yes"
-        ac_boost_path=""
-    else
-        want_boost="yes"
-        ac_boost_path="$withval"
-    fi
-    ],
-    [want_boost="yes"])
-
-
-AC_ARG_WITH([boost-libdir],
-        AS_HELP_STRING([--with-boost-libdir=LIB_DIR],
-        [Force given directory for boost libraries. Note that this will override library path detection, so use this parameter only if default library detection fails and you know exactly where your boost libraries are located.]),
-        [
-        if test -d "$withval"
-        then
-                ac_boost_lib_path="$withval"
-        else
-                AC_MSG_ERROR(--with-boost-libdir expected directory name)
-        fi
-        ],
-        [ac_boost_lib_path=""]
-)
-
-if test "x$want_boost" = "xyes"; then
-    boost_lib_version_req=ifelse([$1], ,1.20.0,$1)
-    boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'`
-    boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'`
-    boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
-    boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
-    if test "x$boost_lib_version_req_sub_minor" = "x" ; then
-        boost_lib_version_req_sub_minor="0"
-        fi
-    WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+  $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor`
-    AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req)
-    succeeded=no
-
-    dnl On 64-bit systems check for system libraries in both lib64 and lib.
-    dnl The former is specified by FHS, but e.g. Debian does not adhere to
-    dnl this (as it rises problems for generic multi-arch support).
-    dnl The last entry in the list is chosen by default when no libraries
-    dnl are found, e.g. when only header-only libraries are installed!
-    libsubdirs="lib"
-    ax_arch=`uname -m`
-    case $ax_arch in
-      x86_64)
-        libsubdirs="lib64 libx32 lib lib64"
-        ;;
-      ppc64|s390x|sparc64|aarch64|ppc64le)
-        libsubdirs="lib64 lib lib64 ppc64le"
-        ;;
-    esac
-
-    dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give
-    dnl them priority over the other paths since, if libs are found there, they
-    dnl are almost assuredly the ones desired.
-    AC_REQUIRE([AC_CANONICAL_HOST])
-    libsubdirs="lib/${host_cpu}-${host_os} $libsubdirs"
-
-    case ${host_cpu} in
-      i?86)
-        libsubdirs="lib/i386-${host_os} $libsubdirs"
-        ;;
-    esac
-
-    dnl first we check the system location for boost libraries
-    dnl this location ist chosen if boost libraries are installed with the --layout=system option
-    dnl or if you install boost with RPM
-    if test "$ac_boost_path" != ""; then
-        BOOST_CPPFLAGS="-I$ac_boost_path/include"
-        for ac_boost_path_tmp in $libsubdirs; do
-                if test -d "$ac_boost_path"/"$ac_boost_path_tmp" ; then
-                        BOOST_LDFLAGS="-L$ac_boost_path/$ac_boost_path_tmp"
-                        break
-                fi
-        done
-    elif test "$cross_compiling" != yes; then
-        for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do
-            if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then
-                for libsubdir in $libsubdirs ; do
-                    if ls "$ac_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
-                done
-                BOOST_LDFLAGS="-L$ac_boost_path_tmp/$libsubdir"
-                BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include"
-                break;
-            fi
-        done
-    fi
-
-    dnl overwrite ld flags if we have required special directory with
-    dnl --with-boost-libdir parameter
-    if test "$ac_boost_lib_path" != ""; then
-       BOOST_LDFLAGS="-L$ac_boost_lib_path"
-    fi
-
-    CPPFLAGS_SAVED="$CPPFLAGS"
-    CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
-    export CPPFLAGS
-
-    LDFLAGS_SAVED="$LDFLAGS"
-    LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
-    export LDFLAGS
-
-    AC_REQUIRE([AC_PROG_CXX])
-    AC_LANG_PUSH(C++)
-        AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-    @%:@include <boost/version.hpp>
-    ]], [[
-    #if BOOST_VERSION >= $WANT_BOOST_VERSION
-    // Everything is okay
-    #else
-    #  error Boost version is too old
-    #endif
-    ]])],[
-        AC_MSG_RESULT(yes)
-    succeeded=yes
-    found_system=yes
-        ],[
-        ])
-    AC_LANG_POP([C++])
-
-
-
-    dnl if we found no boost with system layout we search for boost libraries
-    dnl built and installed without the --layout=system option or for a staged(not installed) version
-    if test "x$succeeded" != "xyes"; then
-        CPPFLAGS="$CPPFLAGS_SAVED"
-        LDFLAGS="$LDFLAGS_SAVED"
-        BOOST_CPPFLAGS=
-        BOOST_LDFLAGS=
-        _version=0
-        if test "$ac_boost_path" != ""; then
-            if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
-                for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
-                    _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
-                    V_CHECK=`expr $_version_tmp \> $_version`
-                    if test "$V_CHECK" = "1" ; then
-                        _version=$_version_tmp
-                    fi
-                    VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
-                    BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
-                done
-                dnl if nothing found search for layout used in Windows distributions
-                if test -z "$BOOST_CPPFLAGS"; then
-                    if test -d "$ac_boost_path/boost" && test -r "$ac_boost_path/boost"; then
-                        BOOST_CPPFLAGS="-I$ac_boost_path"
-                    fi
-                fi
-            fi
-        else
-            if test "$cross_compiling" != yes; then
-                for ac_boost_path in /usr /usr/local /opt /opt/local ; do
-                    if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
-                        for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
-                            _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
-                            V_CHECK=`expr $_version_tmp \> $_version`
-                            if test "$V_CHECK" = "1" ; then
-                                _version=$_version_tmp
-                                best_path=$ac_boost_path
-                            fi
-                        done
-                    fi
-                done
-
-                VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
-                BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
-                if test "$ac_boost_lib_path" = ""; then
-                    for libsubdir in $libsubdirs ; do
-                        if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
-                    done
-                    BOOST_LDFLAGS="-L$best_path/$libsubdir"
-                fi
-            fi
-
-            if test "x$BOOST_ROOT" != "x"; then
-                for libsubdir in $libsubdirs ; do
-                    if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
-                done
-                if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then
-                    version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'`
-                    stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
-                        stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
-                    V_CHECK=`expr $stage_version_shorten \>\= $_version`
-                    if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then
-                        AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
-                        BOOST_CPPFLAGS="-I$BOOST_ROOT"
-                        BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir"
-                    fi
-                fi
-            fi
-        fi
-
-        CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
-        export CPPFLAGS
-        LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
-        export LDFLAGS
-
-        AC_LANG_PUSH(C++)
-            AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        @%:@include <boost/version.hpp>
-        ]], [[
-        #if BOOST_VERSION >= $WANT_BOOST_VERSION
-        // Everything is okay
-        #else
-        #  error Boost version is too old
-        #endif
-        ]])],[
-            AC_MSG_RESULT(yes)
-        succeeded=yes
-        found_system=yes
-            ],[
-            ])
-        AC_LANG_POP([C++])
-    fi
-
-    if test "$succeeded" != "yes" ; then
-        if test "$_version" = "0" ; then
-            AC_MSG_NOTICE([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option.  If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
-        else
-            AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).])
-        fi
-        # execute ACTION-IF-NOT-FOUND (if present):
-        ifelse([$3], , :, [$3])
-    else
-        AC_SUBST(BOOST_CPPFLAGS)
-        AC_SUBST(BOOST_LDFLAGS)
-        AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available])
-        # execute ACTION-IF-FOUND (if present):
-        ifelse([$2], , :, [$2])
-    fi
-
-    CPPFLAGS="$CPPFLAGS_SAVED"
-    LDFLAGS="$LDFLAGS_SAVED"
-fi
-
-])
diff --git a/m4/ax_boost_filesystem.m4 b/m4/ax_boost_filesystem.m4
deleted file mode 100644
index f162163..0000000
--- a/m4/ax_boost_filesystem.m4
+++ /dev/null
@@ -1,118 +0,0 @@
-# ===========================================================================
-#    http://www.gnu.org/software/autoconf-archive/ax_boost_filesystem.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-#   AX_BOOST_FILESYSTEM
-#
-# DESCRIPTION
-#
-#   Test for Filesystem library from the Boost C++ libraries. The macro
-#   requires a preceding call to AX_BOOST_BASE. Further documentation is
-#   available at <http://randspringer.de/boost/index.html>.
-#
-#   This macro calls:
-#
-#     AC_SUBST(BOOST_FILESYSTEM_LIB)
-#
-#   And sets:
-#
-#     HAVE_BOOST_FILESYSTEM
-#
-# LICENSE
-#
-#   Copyright (c) 2009 Thomas Porschberg <thomas at randspringer.de>
-#   Copyright (c) 2009 Michael Tindal
-#   Copyright (c) 2009 Roman Rybalko <libtorrent at romanr.info>
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved. This file is offered as-is, without any
-#   warranty.
-
-#serial 26
-
-AC_DEFUN([AX_BOOST_FILESYSTEM],
-[
-	AC_ARG_WITH([boost-filesystem],
-	AS_HELP_STRING([--with-boost-filesystem@<:@=special-lib@:>@],
-                   [use the Filesystem library from boost - it is possible to specify a certain library for the linker
-                        e.g. --with-boost-filesystem=boost_filesystem-gcc-mt ]),
-        [
-        if test "$withval" = "no"; then
-			want_boost="no"
-        elif test "$withval" = "yes"; then
-            want_boost="yes"
-            ax_boost_user_filesystem_lib=""
-        else
-		    want_boost="yes"
-		ax_boost_user_filesystem_lib="$withval"
-		fi
-        ],
-        [want_boost="yes"]
-	)
-
-	if test "x$want_boost" = "xyes"; then
-        AC_REQUIRE([AC_PROG_CC])
-		CPPFLAGS_SAVED="$CPPFLAGS"
-		CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
-		export CPPFLAGS
-
-		LDFLAGS_SAVED="$LDFLAGS"
-		LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
-		export LDFLAGS
-
-		LIBS_SAVED=$LIBS
-		LIBS="$LIBS $BOOST_SYSTEM_LIB"
-		export LIBS
-
-        AC_CACHE_CHECK(whether the Boost::Filesystem library is available,
-					   ax_cv_boost_filesystem,
-        [AC_LANG_PUSH([C++])
-         AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/filesystem/path.hpp>]],
-                                   [[using namespace boost::filesystem;
-                                   path my_path( "foo/bar/data.txt" );
-                                   return 0;]])],
-					       ax_cv_boost_filesystem=yes, ax_cv_boost_filesystem=no)
-         AC_LANG_POP([C++])
-		])
-		if test "x$ax_cv_boost_filesystem" = "xyes"; then
-			AC_DEFINE(HAVE_BOOST_FILESYSTEM,,[define if the Boost::Filesystem library is available])
-            BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
-            if test "x$ax_boost_user_filesystem_lib" = "x"; then
-                for libextension in `ls -r $BOOSTLIBDIR/libboost_filesystem* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do
-                     ax_lib=${libextension}
-				    AC_CHECK_LIB($ax_lib, exit,
-                                 [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break],
-                                 [link_filesystem="no"])
-				done
-                if test "x$link_filesystem" != "xyes"; then
-                for libextension in `ls -r $BOOSTLIBDIR/boost_filesystem* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do
-                     ax_lib=${libextension}
-				    AC_CHECK_LIB($ax_lib, exit,
-                                 [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break],
-                                 [link_filesystem="no"])
-				done
-		    fi
-            else
-               for ax_lib in $ax_boost_user_filesystem_lib boost_filesystem-$ax_boost_user_filesystem_lib; do
-				      AC_CHECK_LIB($ax_lib, exit,
-                                   [BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break],
-                                   [link_filesystem="no"])
-                  done
-
-            fi
-            if test "x$ax_lib" = "x"; then
-                AC_MSG_ERROR(Could not find a version of the library!)
-            fi
-			if test "x$link_filesystem" != "xyes"; then
-				AC_MSG_ERROR(Could not link against $ax_lib !)
-			fi
-		fi
-
-		CPPFLAGS="$CPPFLAGS_SAVED"
-		LDFLAGS="$LDFLAGS_SAVED"
-		LIBS="$LIBS_SAVED"
-	fi
-])
diff --git a/m4/ax_boost_system.m4 b/m4/ax_boost_system.m4
deleted file mode 100644
index c4c4555..0000000
--- a/m4/ax_boost_system.m4
+++ /dev/null
@@ -1,120 +0,0 @@
-# ===========================================================================
-#      http://www.gnu.org/software/autoconf-archive/ax_boost_system.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-#   AX_BOOST_SYSTEM
-#
-# DESCRIPTION
-#
-#   Test for System library from the Boost C++ libraries. The macro requires
-#   a preceding call to AX_BOOST_BASE. Further documentation is available at
-#   <http://randspringer.de/boost/index.html>.
-#
-#   This macro calls:
-#
-#     AC_SUBST(BOOST_SYSTEM_LIB)
-#
-#   And sets:
-#
-#     HAVE_BOOST_SYSTEM
-#
-# LICENSE
-#
-#   Copyright (c) 2008 Thomas Porschberg <thomas at randspringer.de>
-#   Copyright (c) 2008 Michael Tindal
-#   Copyright (c) 2008 Daniel Casimiro <dan.casimiro at gmail.com>
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved. This file is offered as-is, without any
-#   warranty.
-
-#serial 17
-
-AC_DEFUN([AX_BOOST_SYSTEM],
-[
-	AC_ARG_WITH([boost-system],
-	AS_HELP_STRING([--with-boost-system@<:@=special-lib@:>@],
-                   [use the System library from boost - it is possible to specify a certain library for the linker
-                        e.g. --with-boost-system=boost_system-gcc-mt ]),
-        [
-        if test "$withval" = "no"; then
-			want_boost="no"
-        elif test "$withval" = "yes"; then
-            want_boost="yes"
-            ax_boost_user_system_lib=""
-        else
-		    want_boost="yes"
-		ax_boost_user_system_lib="$withval"
-		fi
-        ],
-        [want_boost="yes"]
-	)
-
-	if test "x$want_boost" = "xyes"; then
-        AC_REQUIRE([AC_PROG_CC])
-        AC_REQUIRE([AC_CANONICAL_BUILD])
-		CPPFLAGS_SAVED="$CPPFLAGS"
-		CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
-		export CPPFLAGS
-
-		LDFLAGS_SAVED="$LDFLAGS"
-		LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
-		export LDFLAGS
-
-        AC_CACHE_CHECK(whether the Boost::System library is available,
-					   ax_cv_boost_system,
-        [AC_LANG_PUSH([C++])
-			 CXXFLAGS_SAVE=$CXXFLAGS
-
-			 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/system/error_code.hpp>]],
-                                   [[boost::system::system_category]])],
-                   ax_cv_boost_system=yes, ax_cv_boost_system=no)
-			 CXXFLAGS=$CXXFLAGS_SAVE
-             AC_LANG_POP([C++])
-		])
-		if test "x$ax_cv_boost_system" = "xyes"; then
-			AC_SUBST(BOOST_CPPFLAGS)
-
-			AC_DEFINE(HAVE_BOOST_SYSTEM,,[define if the Boost::System library is available])
-            BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
-
-			LDFLAGS_SAVE=$LDFLAGS
-            if test "x$ax_boost_user_system_lib" = "x"; then
-                for libextension in `ls -r $BOOSTLIBDIR/libboost_system* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do
-                     ax_lib=${libextension}
-				    AC_CHECK_LIB($ax_lib, exit,
-                                 [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
-                                 [link_system="no"])
-				done
-                if test "x$link_system" != "xyes"; then
-                for libextension in `ls -r $BOOSTLIBDIR/boost_system* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do
-                     ax_lib=${libextension}
-				    AC_CHECK_LIB($ax_lib, exit,
-                                 [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
-                                 [link_system="no"])
-				done
-                fi
-
-            else
-               for ax_lib in $ax_boost_user_system_lib boost_system-$ax_boost_user_system_lib; do
-				      AC_CHECK_LIB($ax_lib, exit,
-                                   [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
-                                   [link_system="no"])
-                  done
-
-            fi
-            if test "x$ax_lib" = "x"; then
-                AC_MSG_ERROR(Could not find a version of the library!)
-            fi
-			if test "x$link_system" = "xno"; then
-				AC_MSG_ERROR(Could not link against $ax_lib !)
-			fi
-		fi
-
-		CPPFLAGS="$CPPFLAGS_SAVED"
-	LDFLAGS="$LDFLAGS_SAVED"
-	fi
-])
diff --git a/m4/ax_boost_thread.m4 b/m4/ax_boost_thread.m4
deleted file mode 100644
index 79e12cd..0000000
--- a/m4/ax_boost_thread.m4
+++ /dev/null
@@ -1,149 +0,0 @@
-# ===========================================================================
-#      http://www.gnu.org/software/autoconf-archive/ax_boost_thread.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-#   AX_BOOST_THREAD
-#
-# DESCRIPTION
-#
-#   Test for Thread library from the Boost C++ libraries. The macro requires
-#   a preceding call to AX_BOOST_BASE. Further documentation is available at
-#   <http://randspringer.de/boost/index.html>.
-#
-#   This macro calls:
-#
-#     AC_SUBST(BOOST_THREAD_LIB)
-#
-#   And sets:
-#
-#     HAVE_BOOST_THREAD
-#
-# LICENSE
-#
-#   Copyright (c) 2009 Thomas Porschberg <thomas at randspringer.de>
-#   Copyright (c) 2009 Michael Tindal
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved. This file is offered as-is, without any
-#   warranty.
-
-#serial 27
-
-AC_DEFUN([AX_BOOST_THREAD],
-[
-	AC_ARG_WITH([boost-thread],
-	AS_HELP_STRING([--with-boost-thread@<:@=special-lib@:>@],
-                   [use the Thread library from boost - it is possible to specify a certain library for the linker
-                        e.g. --with-boost-thread=boost_thread-gcc-mt ]),
-        [
-        if test "$withval" = "no"; then
-			want_boost="no"
-        elif test "$withval" = "yes"; then
-            want_boost="yes"
-            ax_boost_user_thread_lib=""
-        else
-		    want_boost="yes"
-		ax_boost_user_thread_lib="$withval"
-		fi
-        ],
-        [want_boost="yes"]
-	)
-
-	if test "x$want_boost" = "xyes"; then
-        AC_REQUIRE([AC_PROG_CC])
-        AC_REQUIRE([AC_CANONICAL_BUILD])
-		CPPFLAGS_SAVED="$CPPFLAGS"
-		CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
-		export CPPFLAGS
-
-		LDFLAGS_SAVED="$LDFLAGS"
-		LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
-		export LDFLAGS
-
-        AC_CACHE_CHECK(whether the Boost::Thread library is available,
-					   ax_cv_boost_thread,
-        [AC_LANG_PUSH([C++])
-			 CXXFLAGS_SAVE=$CXXFLAGS
-
-			 if test "x$host_os" = "xsolaris" ; then
-				 CXXFLAGS="-pthreads $CXXFLAGS"
-			 elif test "x$host_os" = "xmingw32" ; then
-				 CXXFLAGS="-mthreads $CXXFLAGS"
-			 else
-				CXXFLAGS="-pthread $CXXFLAGS"
-			 fi
-			 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/thread/thread.hpp>]],
-                                   [[boost::thread_group thrds;
-                                   return 0;]])],
-                   ax_cv_boost_thread=yes, ax_cv_boost_thread=no)
-			 CXXFLAGS=$CXXFLAGS_SAVE
-             AC_LANG_POP([C++])
-		])
-		if test "x$ax_cv_boost_thread" = "xyes"; then
-           if test "x$host_os" = "xsolaris" ; then
-			  BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS"
-		   elif test "x$host_os" = "xmingw32" ; then
-			  BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS"
-		   else
-			  BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS"
-		   fi
-
-			AC_SUBST(BOOST_CPPFLAGS)
-
-			AC_DEFINE(HAVE_BOOST_THREAD,,[define if the Boost::Thread library is available])
-            BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
-
-			LDFLAGS_SAVE=$LDFLAGS
-                        case "x$host_os" in
-                          *bsd* )
-                               LDFLAGS="-pthread $LDFLAGS"
-                          break;
-                          ;;
-                        esac
-            if test "x$ax_boost_user_thread_lib" = "x"; then
-                for libextension in `ls -r $BOOSTLIBDIR/libboost_thread* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'`; do
-                     ax_lib=${libextension}
-				    AC_CHECK_LIB($ax_lib, exit,
-                                 [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
-                                 [link_thread="no"])
-				done
-                if test "x$link_thread" != "xyes"; then
-                for libextension in `ls -r $BOOSTLIBDIR/boost_thread* 2>/dev/null | sed 's,.*/,,' | sed 's,\..*,,'`; do
-                     ax_lib=${libextension}
-				    AC_CHECK_LIB($ax_lib, exit,
-                                 [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
-                                 [link_thread="no"])
-				done
-                fi
-
-            else
-               for ax_lib in $ax_boost_user_thread_lib boost_thread-$ax_boost_user_thread_lib; do
-				      AC_CHECK_LIB($ax_lib, exit,
-                                   [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
-                                   [link_thread="no"])
-                  done
-
-            fi
-            if test "x$ax_lib" = "x"; then
-                AC_MSG_ERROR(Could not find a version of the library!)
-            fi
-			if test "x$link_thread" = "xno"; then
-				AC_MSG_ERROR(Could not link against $ax_lib !)
-                        else
-                           case "x$host_os" in
-                              *bsd* )
-				BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS"
-                              break;
-                              ;;
-                           esac
-
-			fi
-		fi
-
-		CPPFLAGS="$CPPFLAGS_SAVED"
-	LDFLAGS="$LDFLAGS_SAVED"
-	fi
-])
diff --git a/m4/ax_cflags_warn_all.m4 b/m4/ax_cflags_warn_all.m4
deleted file mode 100644
index 0fa3e18..0000000
--- a/m4/ax_cflags_warn_all.m4
+++ /dev/null
@@ -1,122 +0,0 @@
-# ===========================================================================
-#    http://www.gnu.org/software/autoconf-archive/ax_cflags_warn_all.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-#   AX_CFLAGS_WARN_ALL   [(shellvar [,default, [A/NA]])]
-#   AX_CXXFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])]
-#   AX_FCFLAGS_WARN_ALL  [(shellvar [,default, [A/NA]])]
-#
-# DESCRIPTION
-#
-#   Try to find a compiler option that enables most reasonable warnings.
-#
-#   For the GNU compiler it will be -Wall (and -ansi -pedantic) The result
-#   is added to the shellvar being CFLAGS, CXXFLAGS, or FCFLAGS by default.
-#
-#   Currently this macro knows about the GCC, Solaris, Digital Unix, AIX,
-#   HP-UX, IRIX, NEC SX-5 (Super-UX 10), Cray J90 (Unicos 10.0.0.8), and
-#   Intel compilers.  For a given compiler, the Fortran flags are much more
-#   experimental than their C equivalents.
-#
-#    - $1 shell-variable-to-add-to : CFLAGS, CXXFLAGS, or FCFLAGS
-#    - $2 add-value-if-not-found : nothing
-#    - $3 action-if-found : add value to shellvariable
-#    - $4 action-if-not-found : nothing
-#
-#   NOTE: These macros depend on AX_APPEND_FLAG.
-#
-# LICENSE
-#
-#   Copyright (c) 2008 Guido U. Draheim <guidod at gmx.de>
-#   Copyright (c) 2010 Rhys Ulerich <rhys.ulerich at gmail.com>
-#
-#   This program is free software; you can redistribute it and/or modify it
-#   under the terms of the GNU General Public License as published by the
-#   Free Software Foundation; either version 3 of the License, or (at your
-#   option) any later version.
-#
-#   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 for more details.
-#
-#   You should have received a copy of the GNU General Public License along
-#   with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-#   As a special exception, the respective Autoconf Macro's copyright owner
-#   gives unlimited permission to copy, distribute and modify the configure
-#   scripts that are the output of Autoconf when processing the Macro. You
-#   need not follow the terms of the GNU General Public License when using
-#   or distributing such scripts, even though portions of the text of the
-#   Macro appear in them. The GNU General Public License (GPL) does govern
-#   all other use of the material that constitutes the Autoconf Macro.
-#
-#   This special exception to the GPL applies to versions of the Autoconf
-#   Macro released by the Autoconf Archive. When you make and distribute a
-#   modified version of the Autoconf Macro, you may extend this special
-#   exception to the GPL to apply to your modified version as well.
-
-#serial 14
-
-AC_DEFUN([AX_FLAGS_WARN_ALL],[dnl
-AS_VAR_PUSHDEF([FLAGS],[_AC_LANG_PREFIX[]FLAGS])dnl
-AS_VAR_PUSHDEF([VAR],[ac_cv_[]_AC_LANG_ABBREV[]flags_warn_all])dnl
-AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings],
-VAR,[VAR="no, unknown"
-ac_save_[]FLAGS="$[]FLAGS"
-for ac_arg dnl
-in "-warn all  % -warn all"   dnl Intel
-   "-pedantic  % -Wall"       dnl GCC
-   "-xstrconst % -v"          dnl Solaris C
-   "-std1      % -verbose -w0 -warnprotos" dnl Digital Unix
-   "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX
-   "-ansi -ansiE % -fullwarn" dnl IRIX
-   "+ESlit     % +w1"         dnl HP-UX C
-   "-Xc        % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10)
-   "-h conform % -h msglevel 2" dnl Cray C (Unicos)
-   #
-do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
-   AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
-                     [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
-done
-FLAGS="$ac_save_[]FLAGS"
-])
-AS_VAR_POPDEF([FLAGS])dnl
-AC_REQUIRE([AX_APPEND_FLAG])
-case ".$VAR" in
-     .ok|.ok,*) m4_ifvaln($3,$3) ;;
-   .|.no|.no,*) m4_default($4,[m4_ifval($2,[AX_APPEND_FLAG([$2], [$1])])]) ;;
-   *) m4_default($3,[AX_APPEND_FLAG([$VAR], [$1])]) ;;
-esac
-AS_VAR_POPDEF([VAR])dnl
-])dnl AX_FLAGS_WARN_ALL
-dnl  implementation tactics:
-dnl   the for-argument contains a list of options. The first part of
-dnl   these does only exist to detect the compiler - usually it is
-dnl   a global option to enable -ansi or -extrawarnings. All other
-dnl   compilers will fail about it. That was needed since a lot of
-dnl   compilers will give false positives for some option-syntax
-dnl   like -Woption or -Xoption as they think of it is a pass-through
-dnl   to later compile stages or something. The "%" is used as a
-dnl   delimiter. A non-option comment can be given after "%%" marks
-dnl   which will be shown but not added to the respective C/CXXFLAGS.
-
-AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl
-AC_LANG_PUSH([C])
-AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
-AC_LANG_POP([C])
-])
-
-AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl
-AC_LANG_PUSH([C++])
-AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
-AC_LANG_POP([C++])
-])
-
-AC_DEFUN([AX_FCFLAGS_WARN_ALL],[dnl
-AC_LANG_PUSH([Fortran])
-AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
-AC_LANG_POP([Fortran])
-])
diff --git a/m4/ax_compare_version.m4 b/m4/ax_compare_version.m4
deleted file mode 100644
index 74dc0fd..0000000
--- a/m4/ax_compare_version.m4
+++ /dev/null
@@ -1,177 +0,0 @@
-# ===========================================================================
-#    http://www.gnu.org/software/autoconf-archive/ax_compare_version.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-#   AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
-#
-# DESCRIPTION
-#
-#   This macro compares two version strings. Due to the various number of
-#   minor-version numbers that can exist, and the fact that string
-#   comparisons are not compatible with numeric comparisons, this is not
-#   necessarily trivial to do in a autoconf script. This macro makes doing
-#   these comparisons easy.
-#
-#   The six basic comparisons are available, as well as checking equality
-#   limited to a certain number of minor-version levels.
-#
-#   The operator OP determines what type of comparison to do, and can be one
-#   of:
-#
-#    eq  - equal (test A == B)
-#    ne  - not equal (test A != B)
-#    le  - less than or equal (test A <= B)
-#    ge  - greater than or equal (test A >= B)
-#    lt  - less than (test A < B)
-#    gt  - greater than (test A > B)
-#
-#   Additionally, the eq and ne operator can have a number after it to limit
-#   the test to that number of minor versions.
-#
-#    eq0 - equal up to the length of the shorter version
-#    ne0 - not equal up to the length of the shorter version
-#    eqN - equal up to N sub-version levels
-#    neN - not equal up to N sub-version levels
-#
-#   When the condition is true, shell commands ACTION-IF-TRUE are run,
-#   otherwise shell commands ACTION-IF-FALSE are run. The environment
-#   variable 'ax_compare_version' is always set to either 'true' or 'false'
-#   as well.
-#
-#   Examples:
-#
-#     AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8])
-#     AX_COMPARE_VERSION([3.15],[lt],[3.15.8])
-#
-#   would both be true.
-#
-#     AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8])
-#     AX_COMPARE_VERSION([3.15],[gt],[3.15.8])
-#
-#   would both be false.
-#
-#     AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8])
-#
-#   would be true because it is only comparing two minor versions.
-#
-#     AX_COMPARE_VERSION([3.15.7],[eq0],[3.15])
-#
-#   would be true because it is only comparing the lesser number of minor
-#   versions of the two values.
-#
-#   Note: The characters that separate the version numbers do not matter. An
-#   empty string is the same as version 0. OP is evaluated by autoconf, not
-#   configure, so must be a string, not a variable.
-#
-#   The author would like to acknowledge Guido Draheim whose advice about
-#   the m4_case and m4_ifvaln functions make this macro only include the
-#   portions necessary to perform the specific comparison specified by the
-#   OP argument in the final configure script.
-#
-# LICENSE
-#
-#   Copyright (c) 2008 Tim Toolan <toolan at ele.uri.edu>
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved. This file is offered as-is, without any
-#   warranty.
-
-#serial 11
-
-dnl #########################################################################
-AC_DEFUN([AX_COMPARE_VERSION], [
-  AC_REQUIRE([AC_PROG_AWK])
-
-  # Used to indicate true or false condition
-  ax_compare_version=false
-
-  # Convert the two version strings to be compared into a format that
-  # allows a simple string comparison.  The end result is that a version
-  # string of the form 1.12.5-r617 will be converted to the form
-  # 0001001200050617.  In other words, each number is zero padded to four
-  # digits, and non digits are removed.
-  AS_VAR_PUSHDEF([A],[ax_compare_version_A])
-  A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
-                     -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
-                     -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
-                     -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
-                     -e 's/[[^0-9]]//g'`
-
-  AS_VAR_PUSHDEF([B],[ax_compare_version_B])
-  B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
-                     -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
-                     -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
-                     -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
-                     -e 's/[[^0-9]]//g'`
-
-  dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary
-  dnl # then the first line is used to determine if the condition is true.
-  dnl # The sed right after the echo is to remove any indented white space.
-  m4_case(m4_tolower($2),
-  [lt],[
-    ax_compare_version=`echo "x$A
-x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"`
-  ],
-  [gt],[
-    ax_compare_version=`echo "x$A
-x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"`
-  ],
-  [le],[
-    ax_compare_version=`echo "x$A
-x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"`
-  ],
-  [ge],[
-    ax_compare_version=`echo "x$A
-x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"`
-  ],[
-    dnl Split the operator from the subversion count if present.
-    m4_bmatch(m4_substr($2,2),
-    [0],[
-      # A count of zero means use the length of the shorter version.
-      # Determine the number of characters in A and B.
-      ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'`
-      ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'`
-
-      # Set A to no more than B's length and B to no more than A's length.
-      A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"`
-      B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"`
-    ],
-    [[0-9]+],[
-      # A count greater than zero means use only that many subversions
-      A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
-      B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
-    ],
-    [.+],[
-      AC_WARNING(
-        [illegal OP numeric parameter: $2])
-    ],[])
-
-    # Pad zeros at end of numbers to make same length.
-    ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`"
-    B="$B`echo $A | sed 's/./0/g'`"
-    A="$ax_compare_version_tmp_A"
-
-    # Check for equality or inequality as necessary.
-    m4_case(m4_tolower(m4_substr($2,0,2)),
-    [eq],[
-      test "x$A" = "x$B" && ax_compare_version=true
-    ],
-    [ne],[
-      test "x$A" != "x$B" && ax_compare_version=true
-    ],[
-      AC_WARNING([illegal OP parameter: $2])
-    ])
-  ])
-
-  AS_VAR_POPDEF([A])dnl
-  AS_VAR_POPDEF([B])dnl
-
-  dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE.
-  if test "$ax_compare_version" = "true" ; then
-    m4_ifvaln([$4],[$4],[:])dnl
-    m4_ifvaln([$5],[else $5])dnl
-  fi
-]) dnl AX_COMPARE_VERSION
diff --git a/m4/ax_compile_check_sizeof.m4 b/m4/ax_compile_check_sizeof.m4
deleted file mode 100644
index 00d0bcc..0000000
--- a/m4/ax_compile_check_sizeof.m4
+++ /dev/null
@@ -1,114 +0,0 @@
-# ===========================================================================
-#  http://www.gnu.org/software/autoconf-archive/ax_compile_check_sizeof.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-#   AX_COMPILE_CHECK_SIZEOF(TYPE [, HEADERS [, EXTRA_SIZES...]])
-#
-# DESCRIPTION
-#
-#   This macro checks for the size of TYPE using compile checks, not run
-#   checks. You can supply extra HEADERS to look into. the check will cycle
-#   through 1 2 4 8 16 and any EXTRA_SIZES the user supplies. If a match is
-#   found, it will #define SIZEOF_`TYPE' to that value. Otherwise it will
-#   emit a configure time error indicating the size of the type could not be
-#   determined.
-#
-#   The trick is that C will not allow duplicate case labels. While this is
-#   valid C code:
-#
-#     switch (0) case 0: case 1:;
-#
-#   The following is not:
-#
-#     switch (0) case 0: case 0:;
-#
-#   Thus, the AC_TRY_COMPILE will fail if the currently tried size does not
-#   match.
-#
-#   Here is an example skeleton configure.in script, demonstrating the
-#   macro's usage:
-#
-#     AC_PROG_CC
-#     AC_CHECK_HEADERS(stddef.h unistd.h)
-#     AC_TYPE_SIZE_T
-#     AC_CHECK_TYPE(ssize_t, int)
-#
-#     headers='#ifdef HAVE_STDDEF_H
-#     #include <stddef.h>
-#     #endif
-#     #ifdef HAVE_UNISTD_H
-#     #include <unistd.h>
-#     #endif
-#     '
-#
-#     AX_COMPILE_CHECK_SIZEOF(char)
-#     AX_COMPILE_CHECK_SIZEOF(short)
-#     AX_COMPILE_CHECK_SIZEOF(int)
-#     AX_COMPILE_CHECK_SIZEOF(long)
-#     AX_COMPILE_CHECK_SIZEOF(unsigned char *)
-#     AX_COMPILE_CHECK_SIZEOF(void *)
-#     AX_COMPILE_CHECK_SIZEOF(size_t, $headers)
-#     AX_COMPILE_CHECK_SIZEOF(ssize_t, $headers)
-#     AX_COMPILE_CHECK_SIZEOF(ptrdiff_t, $headers)
-#     AX_COMPILE_CHECK_SIZEOF(off_t, $headers)
-#
-# LICENSE
-#
-#   Copyright (c) 2008 Kaveh Ghazi <ghazi at caip.rutgers.edu>
-#
-#   This program is free software: you can redistribute it and/or modify it
-#   under the terms of the GNU General Public License as published by the
-#   Free Software Foundation, either version 3 of the License, or (at your
-#   option) any later version.
-#
-#   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 for more details.
-#
-#   You should have received a copy of the GNU General Public License along
-#   with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-#   As a special exception, the respective Autoconf Macro's copyright owner
-#   gives unlimited permission to copy, distribute and modify the configure
-#   scripts that are the output of Autoconf when processing the Macro. You
-#   need not follow the terms of the GNU General Public License when using
-#   or distributing such scripts, even though portions of the text of the
-#   Macro appear in them. The GNU General Public License (GPL) does govern
-#   all other use of the material that constitutes the Autoconf Macro.
-#
-#   This special exception to the GPL applies to versions of the Autoconf
-#   Macro released by the Autoconf Archive. When you make and distribute a
-#   modified version of the Autoconf Macro, you may extend this special
-#   exception to the GPL to apply to your modified version as well.
-
-#serial 5
-
-AU_ALIAS([AC_COMPILE_CHECK_SIZEOF], [AX_COMPILE_CHECK_SIZEOF])
-AC_DEFUN([AX_COMPILE_CHECK_SIZEOF],
-[changequote(<<, >>)dnl
-dnl The name to #define.
-define(<<AC_TYPE_NAME>>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl
-dnl The cache variable name.
-define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl
-changequote([, ])dnl
-AC_MSG_CHECKING(size of $1)
-AC_CACHE_VAL(AC_CV_NAME,
-[for ac_size in 4 8 1 2 16 $3 ; do # List sizes in rough order of prevalence.
-  AC_TRY_COMPILE([#include "confdefs.h"
-#include <sys/types.h>
-$2
-], [switch (0) case 0: case (sizeof ($1) == $ac_size):;], AC_CV_NAME=$ac_size)
-  if test x$AC_CV_NAME != x ; then break; fi
-done
-])
-if test x$AC_CV_NAME = x ; then
-  AC_MSG_ERROR([cannot determine a size for $1])
-fi
-AC_MSG_RESULT($AC_CV_NAME)
-AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME, [The number of bytes in type $1])
-undefine([AC_TYPE_NAME])dnl
-undefine([AC_CV_NAME])dnl
-])
diff --git a/m4/ax_config_nice.m4 b/m4/ax_config_nice.m4
deleted file mode 100644
index 4f87d41..0000000
--- a/m4/ax_config_nice.m4
+++ /dev/null
@@ -1,37 +0,0 @@
-AC_DEFUN([AX_CONFIG_NICE],[
-  config_nice="config.nice"
-  
-  test -f $config_nice && mv $config_nice $config_nice.old
-  rm -f $config_nice.old
-  cat >$config_nice <<EOF
-#! /bin/sh
-#
-# Created by configure
-
-EOF
-
-  for var in CC CFLAGS CPP CPPFLAGS CXX CXXFLAGS LDFLAGS LIBS; do
-    eval val=\$$var
-    if test -n "$val"; then
-      echo "$var='$val' \\" >> $config_nice
-    fi
-  done
-
-  echo "'[$]0' \\" >> $config_nice
-
-  for arg in $ac_configure_args; do
-     if test `expr -- $arg : "'.*"` = 0; then
-        if test `expr -- $arg : "--.*"` = 0; then
-       	  break;
-        fi
-        echo "'[$]arg' \\" >> $config_nice
-     else
-        if test `expr -- $arg : "'--.*"` = 0; then
-       	  break;
-        fi
-        echo "[$]arg \\" >> $config_nice
-     fi
-  done
-  echo '"[$]@"' >> $config_nice
-  chmod 755 $config_nice
-])
diff --git a/m4/ax_cxx_compile_stdcxx_11.m4 b/m4/ax_cxx_compile_stdcxx_11.m4
deleted file mode 100644
index 163a4c6..0000000
--- a/m4/ax_cxx_compile_stdcxx_11.m4
+++ /dev/null
@@ -1,142 +0,0 @@
-# ============================================================================
-#  http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
-# ============================================================================
-#
-# SYNOPSIS
-#
-#   AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
-#
-# DESCRIPTION
-#
-#   Check for baseline language coverage in the compiler for the C++11
-#   standard; if necessary, add switches to CXXFLAGS to enable support.
-#
-#   The first argument, if specified, indicates whether you insist on an
-#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
-#   -std=c++11).  If neither is specified, you get whatever works, with
-#   preference for an extended mode.
-#
-#   The second argument, if specified 'mandatory' or if left unspecified,
-#   indicates that baseline C++11 support is required and that the macro
-#   should error out if no mode with that support is found.  If specified
-#   'optional', then configuration proceeds regardless, after defining
-#   HAVE_CXX11 if and only if a supporting mode is found.
-#
-# LICENSE
-#
-#   Copyright (c) 2008 Benjamin Kosnik <bkoz at redhat.com>
-#   Copyright (c) 2012 Zack Weinberg <zackw at panix.com>
-#   Copyright (c) 2013 Roy Stogner <roystgnr at ices.utexas.edu>
-#   Copyright (c) 2014 Alexey Sokolov <sokolov at google.com>
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved. This file is offered as-is, without any
-#   warranty.
-
-#serial 4
-
-m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[
-  template <typename T>
-    struct check
-    {
-      static_assert(sizeof(int) <= sizeof(T), "not big enough");
-    };
-
-    struct Base {
-    virtual void f() {}
-    };
-    struct Child : public Base {
-    virtual void f() override {}
-    };
-
-    typedef check<check<bool>> right_angle_brackets;
-
-    int a;
-    decltype(a) b;
-
-    typedef check<int> check_type;
-    check_type c;
-    check_type&& cr = static_cast<check_type&&>(c);
-
-    auto d = a;
-    auto l = [](){};
-]])
-
-AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
-  m4_if([$1], [], [],
-        [$1], [ext], [],
-        [$1], [noext], [],
-        [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
-  m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
-        [$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
-        [$2], [optional], [ax_cxx_compile_cxx11_required=false],
-        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])
-  AC_LANG_PUSH([C++])dnl
-  ac_success=no
-  AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
-  ax_cv_cxx_compile_cxx11,
-  [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
-    [ax_cv_cxx_compile_cxx11=yes],
-    [ax_cv_cxx_compile_cxx11=no])])
-  if test x$ax_cv_cxx_compile_cxx11 = xyes; then
-    ac_success=yes
-  fi
-
-  m4_if([$1], [noext], [], [dnl
-  if test x$ac_success = xno; then
-    for switch in -std=gnu++11 -std=gnu++0x; do
-      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
-      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
-                     $cachevar,
-        [ac_save_CXXFLAGS="$CXXFLAGS"
-         CXXFLAGS="$CXXFLAGS $switch"
-         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
-          [eval $cachevar=yes],
-          [eval $cachevar=no])
-         CXXFLAGS="$ac_save_CXXFLAGS"])
-      if eval test x\$$cachevar = xyes; then
-        CXXFLAGS="$CXXFLAGS $switch"
-        ac_success=yes
-        break
-      fi
-    done
-  fi])
-
-  m4_if([$1], [ext], [], [dnl
-  if test x$ac_success = xno; then
-    for switch in -std=c++11 -std=c++0x; do
-      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
-      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
-                     $cachevar,
-        [ac_save_CXXFLAGS="$CXXFLAGS"
-         CXXFLAGS="$CXXFLAGS $switch"
-         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
-          [eval $cachevar=yes],
-          [eval $cachevar=no])
-         CXXFLAGS="$ac_save_CXXFLAGS"])
-      if eval test x\$$cachevar = xyes; then
-        CXXFLAGS="$CXXFLAGS $switch"
-        ac_success=yes
-        break
-      fi
-    done
-  fi])
-  AC_LANG_POP([C++])
-  if test x$ax_cxx_compile_cxx11_required = xtrue; then
-    if test x$ac_success = xno; then
-      AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
-    fi
-  else
-    if test x$ac_success = xno; then
-      HAVE_CXX11=0
-      AC_MSG_NOTICE([No compiler with C++11 support was found])
-    else
-      HAVE_CXX11=1
-      AC_DEFINE(HAVE_CXX11,1,
-                [define if the compiler supports basic C++11 syntax])
-    fi
-
-    AC_SUBST(HAVE_CXX11)
-  fi
-])
diff --git a/m4/ax_lib_bzip2.m4 b/m4/ax_lib_bzip2.m4
deleted file mode 100644
index 04dac11..0000000
--- a/m4/ax_lib_bzip2.m4
+++ /dev/null
@@ -1,221 +0,0 @@
-# SYNOPSIS
-#
-#   AX_LIB_BZIP2()
-#
-# DESCRIPTION
-#
-#   This macro provides tests of availability of the bzip2
-#   compression library. This macro checks for bzip2
-#   headers and libraries and defines compilation flags
-#
-#   Macro supports following options and their values:
-#
-#   1) Single-option usage:
-#
-#     --with-bzip2      -- yes, no, or path to bzip2 library 
-#                          installation prefix
-#
-#   2) Three-options usage (all options are required):
-#
-#     --with-bzip2=yes
-#     --with-bzip2-inc  -- path to base directory with bzip2 headers
-#     --with-bzip2-lib  -- linker flags for bzip2
-#
-#   This macro calls:
-#
-#     AC_SUBST(BZIP2_CFLAGS)
-#     AC_SUBST(BZIP2_LDFLAGS)
-#     AC_SUBST(BZIP2_LiBS)
-#
-#   And sets:
-#
-#     HAVE_BZIP2
-#
-# LICENSE
-#
-#   Copyright (c) 2009 Hartmut Holzgraefe <hartmut at php.net>
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved.
-
-AC_DEFUN([AX_LIB_BZIP2],
-[
-    AC_ARG_WITH([bzip2],
-        AC_HELP_STRING([--with-bzip2=@<:@ARG@:>@],
-            [use bzip2 library from given prefix (ARG=path); check standard prefixes (ARG=yes); disable (ARG=no)]
-        ),
-        [
-        if test "$withval" = "yes"; then
-            if test -f /usr/local/include/bzlib.h ; then
-                bzlib_prefix=/usr/local
-            elif test -f /usr/include/bzlib.h ; then
-                bzlib_prefix=/usr
-            else
-                bzlib_prefix=""
-            fi
-            bzlib_requested="yes"
-        elif test -d "$withval"; then
-            bzlib_prefix="$withval"
-            bzlib_requested="yes"
-        else
-            bzlib_prefix=""
-            bzlib_requested="no"
-        fi
-        ],
-        [
-        dnl Default behavior is implicit yes
-        if test -f /usr/local/include/bzlib.h ; then
-            bzlib_prefix=/usr/local
-        elif test -f /usr/include/bzlib.h ; then
-            bzlib_prefix=/usr
-        else
-            bzlib_prefix=""
-        fi
-        ]
-    )
-
-    AC_ARG_WITH([bzip2-inc],
-        AC_HELP_STRING([--with-bzip2-inc=@<:@DIR@:>@],
-            [path to bzip2 library headers]
-        ),
-        [bzlib_include_dir="$withval"],
-        [bzlib_include_dir=""]
-    )
-    AC_ARG_WITH([bzip2-lib],
-        AC_HELP_STRING([--with-bzip2-lib=@<:@ARG@:>@],
-            [link options for bzip2 library]
-        ),
-        [bzlib_lib_flags="$withval"],
-        [bzlib_lib_flags=""]
-    )
-
-    BZIP2_CFLAGS=""
-    BZIP2_LDFLAGS=""
-    BZIP2_LIBS=""
-
-    dnl
-    dnl Collect include/lib paths and flags
-    dnl
-    run_bzlib_test="no"
-
-    if test -n "$bzlib_prefix"; then
-        bzlib_include_dir="$bzlib_prefix/include"
-        bzlib_lib_flags="-L$bzlib_prefix/lib"
-        bzlib_lib_libs="-lbz2"
-        run_bzlib_test="yes"
-    elif test "$bzlib_requested" = "yes"; then
-        if test -n "$bzlib_include_dir" -a -n "$bzlib_lib_flags" -a -n "$bzlib_lib_libs"; then
-            run_bzlib_test="yes"
-        fi
-    else
-        run_bzlib_test="no"
-    fi
-
-    dnl
-    dnl Check bzip2 files
-    dnl
-    if test "$run_bzlib_test" = "yes"; then
-
-        saved_CPPFLAGS="$CPPFLAGS"
-        CPPFLAGS="$CPPFLAGS -I$bzlib_include_dir"
-
-        saved_LDFLAGS="$LDFLAGS"
-        LDFLAGS="$LDFLAGS $bzlib_lib_flags"
-
-        saved_LIBSS="$LIBS"
-        LIBS="$LIBS $bzlib_lib_libs"
-
-        dnl
-        dnl Check bzip2 headers
-        dnl
-        AC_MSG_CHECKING([for bzip2 headers in $bzlib_include_dir])
-
-        AC_LANG_PUSH([C++])
-        AC_COMPILE_IFELSE([
-            AC_LANG_PROGRAM(
-                [[
-@%:@include <bzlib.h>
-                ]],
-                [[]]
-            )],
-            [
-            BZIP2_CFLAGS="-I$bzlib_include_dir"
-            bzlib_header_found="yes"
-            AC_MSG_RESULT([found])
-            ],
-            [
-            bzlib_header_found="no"
-            AC_MSG_RESULT([not found])
-            ]
-        )
-        AC_LANG_POP([C++])
-
-        dnl
-        dnl Check bzip2 libraries
-        dnl
-        if test "$bzlib_header_found" = "yes"; then
-
-            AC_MSG_CHECKING([for bzip2 library])
-
-            AC_LANG_PUSH([C++])
-            AC_LINK_IFELSE([
-                AC_LANG_PROGRAM(
-                    [[
-@%:@include <bzlib.h>
-                    ]],
-                    [[
-    const char *version;
-    
-    version = BZ2_bzlibVersion();
-                    ]]
-                )],
-                [
-                BZIP2_LDFLAGS="$bzlib_lib_flags"
-                BZIP2_LIBS="$bzlib_lib_libs"
-                bzlib_lib_found="yes"
-                AC_MSG_RESULT([found])
-                ],
-                [
-                bzlib_lib_found="no"
-                AC_MSG_RESULT([not found])
-                ]
-            )
-            AC_LANG_POP([C++])
-        fi
-
-        CPPFLAGS="$saved_CPPFLAGS"
-        LDFLAGS="$saved_LDFLAGS"
-        LIBS="$saved_LIBS"
-    fi
-
-    AC_MSG_CHECKING([for bzip2 compression library])
-
-    if test "$run_bzlib_test" = "yes"; then
-        if test "$bzlib_header_found" = "yes" -a "$bzlib_lib_found" = "yes"; then
-            AC_SUBST([BZIP2_CFLAGS])
-            AC_SUBST([BZIP2_LDFLAGS])
-            AC_SUBST([BZIP2_LIBS])
-            AC_SUBST([HAVE_BZIP2])
-
-            AC_DEFINE([HAVE_BZIP2], [1],
-                [Define to 1 if bzip2 library is available])
-
-            HAVE_BZIP2="yes"
-        else
-            HAVE_BZIP2="no"
-        fi
-
-        AC_MSG_RESULT([$HAVE_BZIP2])
-
-
-    else
-        HAVE_BZIP2="no"
-        AC_MSG_RESULT([$HAVE_BZIP2])
-
-        if test "$bzlib_requested" = "yes"; then
-            AC_MSG_WARN([bzip2 compression support requested but headers or library not found. Specify valid prefix of bzip2 using --with-bzip2=@<:@DIR@:>@ or provide include directory and linker flags using --with-bzip2-inc and --with-bzip2-lib])
-        fi
-    fi
-])
-
diff --git a/m4/ax_lib_geos.m4 b/m4/ax_lib_geos.m4
deleted file mode 100644
index 6ff4fe3..0000000
--- a/m4/ax_lib_geos.m4
+++ /dev/null
@@ -1,161 +0,0 @@
-# SYNOPSIS
-#
-#   AX_LIB_GEOS([MINIMUM-VERSION])
-#
-# DESCRIPTION
-#
-#   This macro provides tests of availability of geos 'libgeos' library
-#   of particular version or newer.
-#
-#   AX_LIB_GEOS macro takes only one argument which is optional. If
-#   there is no required version passed, then macro does not run version
-#   test.
-#
-#   The --with-geos option takes one of three possible values:
-#
-#   no - do not check for geos library
-#
-#   yes - do check for geos library in standard locations (geos-config
-#   should be in the PATH)
-#
-#   path - complete path to geos-config utility, use this option if geos-config
-#   can't be found in the PATH
-#
-#   This macro calls:
-#
-#     AC_SUBST(GEOS_CFLAGS)
-#     AC_SUBST(GEOS_LDFLAGS)
-#     AC_SUBST(GEOS_LIBS)
-#     AC_SUBST(GEOS_VERSION)
-#
-#   And sets:
-#
-#     HAVE_GEOS
-#
-# LICENSE
-#
-#   Copyright (c) 2009 Hartmut Holzgraefe <hartmut at php.net>
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved.
-
-AC_DEFUN([AX_LIB_GEOS],
-[
-    AC_ARG_WITH([geos],
-        AC_HELP_STRING([--with-geos=@<:@ARG@:>@],
-            [use geos library @<:@default=yes@:>@, optionally specify path to geos-config]
-        ),
-        [
-        if test "$withval" = "no"; then
-            want_geos="no"
-        elif test "$withval" = "yes"; then
-            want_geos="yes"
-        else
-            want_geos="yes"
-            GEOS_CONFIG="$withval"
-        fi
-        ],
-        [want_geos="yes"]
-    )
-
-    GEOS_CFLAGS=""
-    GEOS_LDFLAGS=""
-    GEOS_LIBS=""
-    GEOS_VERSION=""
-
-    dnl
-    dnl Check geos libraries (geos)
-    dnl
-
-    if test "$want_geos" = "yes"; then
-
-        if test -z "$GEOS_CONFIG" -o test; then
-            AC_PATH_PROG([GEOS_CONFIG], [geos-config], [])
-        fi
-
-        if test ! -x "$GEOS_CONFIG"; then
-            AC_MSG_ERROR([${GEOS_CONFIG:-geos-config} does not exist or it is not an exectuable file])
-            GEOS_CONFIG="no"
-            found_geos="no"
-        fi
-
-        if test "$GEOS_CONFIG" != "no"; then
-            AC_MSG_CHECKING([for geos libraries])
-
-            GEOS_CFLAGS="`$GEOS_CONFIG --cflags`"
-            GEOS_LDFLAGS="`$GEOS_CONFIG --ldflags`"
-            GEOS_LIBS="`$GEOS_CONFIG --libs`"
-
-            GEOS_VERSION=`$GEOS_CONFIG --version`
-
-            dnl Headers are in a different package in Debian, so check again.
-            ac_save_CPPFLAGS="$CPPFLAGS"
-            CPPFLAGS="$CPPFLAGS $GEOS_CFLAGS"
-            AC_CHECK_HEADER([geos/version.h], [],
-                             [AC_MSG_ERROR([development headers for geos not found])])
-            CPPFLAGS="$ac_save_CPPFLAGS"
-
-            AC_DEFINE([HAVE_GEOS], [1],
-                [Define to 1 if geos libraries are available])
-
-            found_geos="yes"
-            AC_MSG_RESULT([yes])
-        else
-            found_geos="no"
-            AC_MSG_RESULT([no])
-        fi
-    fi
-
-    dnl
-    dnl Check if required version of geos is available
-    dnl
-
-
-    geos_version_req=ifelse([$1], [], [], [$1])
-
-
-    if test "$found_geos" = "yes" -a -n "$geos_version_req"; then
-
-        AC_MSG_CHECKING([if geos version is >= $geos_version_req])
-
-        dnl Decompose required version string of geos
-        dnl and calculate its number representation
-        geos_version_req_major=`expr $geos_version_req : '\([[0-9]]*\)'`
-        geos_version_req_minor=`expr $geos_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
-        geos_version_req_micro=`expr $geos_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
-        if test "x$geos_version_req_micro" = "x"; then
-            geos_version_req_micro="0"
-        fi
-
-        geos_version_req_number=`expr $geos_version_req_major \* 1000000 \
-                                   \+ $geos_version_req_minor \* 1000 \
-                                   \+ $geos_version_req_micro`
-
-        dnl Decompose version string of installed PostgreSQL
-        dnl and calculate its number representation
-        geos_version_major=`expr $GEOS_VERSION : '\([[0-9]]*\)'`
-        geos_version_minor=`expr $GEOS_VERSION : '[[0-9]]*\.\([[0-9]]*\)'`
-        geos_version_micro=`expr $GEOS_VERSION : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
-        if test "x$geos_version_micro" = "x"; then
-            geos_version_micro="0"
-        fi
-
-        geos_version_number=`expr $geos_version_major \* 1000000 \
-                                   \+ $geos_version_minor \* 1000 \
-                                   \+ $geos_version_micro`
-
-        geos_version_check=`expr $geos_version_number \>\= $geos_version_req_number`
-        if test "$geos_version_check" = "1"; then
-            AC_MSG_RESULT([yes])
-        else
-            AC_MSG_RESULT([no])
-        fi
-    fi
-
-    AC_SUBST([GEOS_VERSION])
-    AC_SUBST([GEOS_CFLAGS])
-    AC_SUBST([GEOS_LDFLAGS])
-    AC_SUBST([GEOS_LIBS])
-])
-
diff --git a/m4/ax_lib_postgresql.m4 b/m4/ax_lib_postgresql.m4
deleted file mode 100644
index 51ae4d8..0000000
--- a/m4/ax_lib_postgresql.m4
+++ /dev/null
@@ -1,164 +0,0 @@
-# ===========================================================================
-#     http://www.gnu.org/software/autoconf-archive/ax_lib_postgresql.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-#   AX_LIB_POSTGRESQL([MINIMUM-VERSION])
-#
-# DESCRIPTION
-#
-#   This macro provides tests of availability of PostgreSQL 'libpq' library
-#   of particular version or newer.
-#
-#   AX_LIB_POSTGRESQL macro takes only one argument which is optional. If
-#   there is no required version passed, then macro does not run version
-#   test.
-#
-#   The --with-postgresql option takes one of three possible values:
-#
-#   no - do not check for PostgreSQL client library
-#
-#   yes - do check for PostgreSQL library in standard locations (pg_config
-#   should be in the PATH)
-#
-#   path - complete path to pg_config utility, use this option if pg_config
-#   can't be found in the PATH
-#
-#   This macro calls:
-#
-#     AC_SUBST(POSTGRESQL_CPPFLAGS)
-#     AC_SUBST(POSTGRESQL_LDFLAGS)
-#     AC_SUBST(POSTGRESQL_LIBS)
-#     AC_SUBST(POSTGRESQL_VERSION)
-#
-#   And sets:
-#
-#     HAVE_POSTGRESQL
-#
-# LICENSE
-#
-#   Copyright (c) 2008 Mateusz Loskot <mateusz at loskot.net>
-#   Copyright (c) 2014 Sree Harsha Totakura <sreeharsha at totakura.in>
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved. This file is offered as-is, without any
-#   warranty.
-
-#serial 12
-
-AC_DEFUN([AX_LIB_POSTGRESQL],
-[
-    AC_ARG_WITH([postgresql],
-        AS_HELP_STRING([--with-postgresql=@<:@ARG@:>@],
-            [use PostgreSQL library @<:@default=yes@:>@, optionally specify path to pg_config]
-        ),
-        [
-        if test "$withval" = "no"; then
-            want_postgresql="no"
-        elif test "$withval" = "yes"; then
-            want_postgresql="yes"
-        else
-            want_postgresql="yes"
-            PG_CONFIG="$withval"
-        fi
-        ],
-        [want_postgresql="yes"]
-    )
-
-    POSTGRESQL_CPPFLAGS=""
-    POSTGRESQL_LDFLAGS=""
-    POSTGRESQL_LIBS=""
-    POSTGRESQL_VERSION=""
-
-    dnl
-    dnl Check PostgreSQL libraries (libpq)
-    dnl
-
-    if test "$want_postgresql" = "yes"; then
-
-        if test -z "$PG_CONFIG" -o test; then
-            AC_PATH_PROG([PG_CONFIG], [pg_config], [])
-        fi
-
-        if test ! -x "$PG_CONFIG"; then
-            AC_MSG_ERROR([$PG_CONFIG does not exist or it is not an exectuable file])
-            PG_CONFIG="no"
-            found_postgresql="no"
-        fi
-
-        if test "$PG_CONFIG" != "no"; then
-            AC_MSG_CHECKING([for PostgreSQL libraries])
-
-            POSTGRESQL_CPPFLAGS="-I`$PG_CONFIG --includedir`"
-            POSTGRESQL_LDFLAGS="-L`$PG_CONFIG --libdir`"
-            POSTGRESQL_LIBS="-lpq"
-            POSTGRESQL_VERSION=`$PG_CONFIG --version | sed -e 's#PostgreSQL ##'`
-
-            AC_DEFINE([HAVE_POSTGRESQL], [1],
-                [Define to 1 if PostgreSQL libraries are available])
-
-            found_postgresql="yes"
-            AC_MSG_RESULT([yes])
-        else
-            found_postgresql="no"
-            AC_MSG_RESULT([no])
-        fi
-    fi
-
-    dnl
-    dnl Check if required version of PostgreSQL is available
-    dnl
-
-
-    postgresql_version_req=ifelse([$1], [], [], [$1])
-
-    if test "$found_postgresql" = "yes" -a -n "$postgresql_version_req"; then
-
-        AC_MSG_CHECKING([if PostgreSQL version is >= $postgresql_version_req])
-
-        dnl Decompose required version string of PostgreSQL
-        dnl and calculate its number representation
-        postgresql_version_req_major=`expr $postgresql_version_req : '\([[0-9]]*\)'`
-        postgresql_version_req_minor=`expr $postgresql_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
-        postgresql_version_req_micro=`expr $postgresql_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
-        if test "x$postgresql_version_req_micro" = "x"; then
-            postgresql_version_req_micro="0"
-        fi
-
-        postgresql_version_req_number=`expr $postgresql_version_req_major \* 1000000 \
-                                   \+ $postgresql_version_req_minor \* 1000 \
-                                   \+ $postgresql_version_req_micro`
-
-        dnl Decompose version string of installed PostgreSQL
-        dnl and calculate its number representation
-        postgresql_version_major=`expr $POSTGRESQL_VERSION : '\([[0-9]]*\)'`
-        postgresql_version_minor=`expr $POSTGRESQL_VERSION : '[[0-9]]*\.\([[0-9]]*\)'`
-        postgresql_version_micro=`expr $POSTGRESQL_VERSION : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
-        if test "x$postgresql_version_micro" = "x"; then
-            postgresql_version_micro="0"
-        fi
-
-        postgresql_version_number=`expr $postgresql_version_major \* 1000000 \
-                                   \+ $postgresql_version_minor \* 1000 \
-                                   \+ $postgresql_version_micro`
-
-        postgresql_version_check=`expr $postgresql_version_number \>\= $postgresql_version_req_number`
-        if test "$postgresql_version_check" = "1"; then
-            AC_MSG_RESULT([yes])
-        else
-            AC_MSG_RESULT([no])
-            AC_DEFINE([HAVE_POSTGRESQL], [0],
-                [A required version of PostgreSQL is not found])
-            POSTGRESQL_CPPFLAGS=""
-            POSTGRESQL_LDFLAGS=""
-            POSTGRESQL_LIBS=""
-        fi
-    fi
-
-    AC_SUBST([POSTGRESQL_VERSION])
-    AC_SUBST([POSTGRESQL_CPPFLAGS])
-    AC_SUBST([POSTGRESQL_LDFLAGS])
-    AC_SUBST([POSTGRESQL_LIBS])
-])
diff --git a/m4/ax_lib_proj.m4 b/m4/ax_lib_proj.m4
deleted file mode 100644
index 39999d5..0000000
--- a/m4/ax_lib_proj.m4
+++ /dev/null
@@ -1,216 +0,0 @@
-# SYNOPSIS
-#
-#   AX_LIB_PROJ()
-#
-# DESCRIPTION
-#
-#   This macro provides tests of availability of the proj
-#   projection library. This macro checks for proj
-#   headers and libraries and defines compilation flags
-#
-#   Macro supports following options and their values:
-#
-#   1) Single-option usage:
-#
-#     --with-proj      -- yes, no, or path to proj library 
-#                          installation prefix
-#
-#   2) Three-options usage (all options are required):
-#
-#     --with-proj=yes
-#     --with-proj-inc  -- path to base directory with proj headers
-#     --with-proj-lib  -- linker flags for proj
-#
-#   This macro calls:
-#
-#     AC_SUBST(PROJ_CFLAGS)
-#     AC_SUBST(PROJ_LDFLAGS)
-#     AC_SUBST(PROJ_LIBSS)
-#
-#   And sets:
-#
-#     HAVE_PROJ
-#
-# LICENSE
-#
-#   Copyright (c) 2009 Hartmut Holzgraefe <hartmut at php.net>
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved.
-
-AC_DEFUN([AX_LIB_PROJ],
-[
-    AC_ARG_WITH([proj],
-        AC_HELP_STRING([--with-proj=@<:@ARG@:>@],
-            [use proj library from given prefix (ARG=path); check standard prefixes (ARG=yes); disable (ARG=no)]
-        ),
-        [
-        if test "$withval" = "yes"; then
-            if test -f /usr/local/include/proj_api.h ; then
-                proj_prefix=/usr/local
-            elif test -f /usr/include/proj_api.h ; then
-                proj_prefix=/usr
-            else
-                proj_prefix=""
-            fi
-            proj_requested="yes"
-        elif test -d "$withval"; then
-            proj_prefix="$withval"
-            proj_requested="yes"
-        else
-            proj_prefix=""
-            proj_requested="no"
-        fi
-        ],
-        [
-        dnl Default behavior is implicit yes
-        if test -f /usr/local/include/proj_api.h ; then
-            proj_prefix=/usr/local
-        elif test -f /usr/include/proj_api.h ; then
-            proj_prefix=/usr
-        else
-            proj_prefix=""
-        fi
-        ]
-    )
-
-    AC_ARG_WITH([proj-inc],
-        AC_HELP_STRING([--with-proj-inc=@<:@DIR@:>@],
-            [path to proj library headers]
-        ),
-        [proj_include_dir="$withval"],
-        [proj_include_dir=""]
-    )
-    AC_ARG_WITH([proj-lib],
-        AC_HELP_STRING([--with-proj-lib=@<:@ARG@:>@],
-            [link options for proj library]
-        ),
-        [proj_lib_flags="$withval"],
-        [proj_lib_flags=""]
-    )
-
-    PROJ_CFLAGS=""
-    PROJ_LDFLAGS=""
-    PROJ_LIBS=""
-
-    dnl
-    dnl Collect include/lib paths and flags
-    dnl
-    run_proj_test="no"
-
-    if test -n "$proj_prefix"; then
-        proj_include_dir="$proj_prefix/include"
-        proj_lib_flags="-L$proj_prefix/lib"
-        proj_lib_libs="-lproj"
-        run_proj_test="yes"
-    elif test "$proj_requested" = "yes"; then
-        if test -n "$proj_include_dir" -a -n "$proj_lib_flags" -a -n "$proj_lib_libs"; then
-            run_proj_test="yes"
-        fi
-    else
-        run_proj_test="no"
-    fi
-
-    dnl
-    dnl Check proj files
-    dnl
-    if test "$run_proj_test" = "yes"; then
-
-        saved_CPPFLAGS="$CPPFLAGS"
-        CPPFLAGS="$CPPFLAGS -I$proj_include_dir"
-
-        saved_LDFLAGS="$LDFLAGS"
-        LDFLAGS="$LDFLAGS $proj_lib_flags"
-
-        saved_LIBS="$LIBS"
-        LIBS="$LIBS $proj_lib_libs"
-
-        dnl
-        dnl Check proj headers
-        dnl
-        AC_MSG_CHECKING([for proj headers in $proj_include_dir])
-
-        AC_LANG_PUSH([C++])
-        AC_COMPILE_IFELSE([
-            AC_LANG_PROGRAM(
-                [[
-@%:@include <proj_api.h>
-                ]],
-                [[]]
-            )],
-            [
-            PROJ_CFLAGS="-I$proj_include_dir"
-            proj_header_found="yes"
-            AC_MSG_RESULT([found])
-            ],
-            [
-            proj_header_found="no"
-            AC_MSG_RESULT([not found])
-            ]
-        )
-        AC_LANG_POP([C++])
-
-        dnl
-        dnl Check proj libraries
-        dnl
-        if test "$proj_header_found" = "yes"; then
-
-            AC_MSG_CHECKING([for proj library])
-
-            AC_LANG_PUSH([C++])
-            AC_LINK_IFELSE([
-                AC_LANG_PROGRAM(
-                    [[
-@%:@include <proj_api.h>
-                    ]],
-                    [[
-    /* TODO add a real test */
-                    ]]
-                )],
-                [
-                PROJ_LDFLAGS="$proj_lib_flags"
-                PROJ_LIBS="$proj_lib_libs"
-                proj_lib_found="yes"
-                AC_MSG_RESULT([found])
-                ],
-                [
-                proj_lib_found="no"
-                AC_MSG_RESULT([not found])
-                ]
-            )
-            AC_LANG_POP([C++])
-        fi
-
-        CPPFLAGS="$saved_CPPFLAGS"
-        LDFLAGS="$saved_LDFLAGS"
-        LIBS="$saved_LIBS"
-    fi
-
-    AC_MSG_CHECKING([for proj projection library])
-
-    if test "$run_proj_test" = "yes"; then
-        if test "$proj_header_found" = "yes" -a "$proj_lib_found" = "yes"; then
-
-            AC_SUBST([PROJ_CFLAGS])
-            AC_SUBST([PROJ_LDFLAGS])
-            AC_SUBST([PROJ_LIBS])
-
-            HAVE_PROJ="yes"
-        else
-            HAVE_PROJ="no"
-        fi
-
-        AC_MSG_RESULT([$HAVE_PROJ])
-
-
-    else
-        HAVE_PROJ="no"
-        AC_MSG_RESULT([$HAVE_PROJ])
-
-        if test "$proj_requested" = "yes"; then
-            AC_MSG_WARN([proj projection support requested but headers or library not found. Specify valid prefix of proj using --with-proj=@<:@DIR@:>@ or provide include directory and linker flags using --with-proj-inc and --with-proj-lib])
-        fi
-    fi
-])
-
diff --git a/m4/ax_lib_protobuf_c.m4 b/m4/ax_lib_protobuf_c.m4
deleted file mode 100644
index 38fb151..0000000
--- a/m4/ax_lib_protobuf_c.m4
+++ /dev/null
@@ -1,257 +0,0 @@
-# SYNOPSIS
-#
-#   AX_LIB_PROTOBUF_C()
-#
-# DESCRIPTION
-#
-#   This macro provides tests of availability of the Google
-#   Protocol Buffers C library. This macro checks for protobufr-c
-#   headers and libraries and defines compilation flags
-#
-#   Macro supports following options and their values:
-#
-#   1) Single-option usage:
-#
-#     --with-protobuf_c      -- yes, no, or path to protobuf_c library 
-#                          installation prefix
-#
-#   2) Three-options usage (all options are required):
-#
-#     --with-protobuf_c=yes
-#     --with-protobuf_c-inc  -- path to base directory with protobuf_c headers
-#     --with-protobuf_c-lib  -- linker flags for protobuf_c
-#
-#   This macro calls:
-#
-#     AC_SUBST(PROTOBUF_C_CFLAGS)
-#     AC_SUBST(PROTOBUF_C_LDFLAGS)
-#     AC_SUBST(PROTOBUF_C_LIBS)
-#
-#   And sets:
-#
-#     HAVE_PROTOBUF_C
-#
-# LICENSE
-#
-#   Copyright (c) 2009 Hartmut Holzgraefe <hartmut at php.net>
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved.
-
-AC_DEFUN([AX_LIB_PROTOBUF_C],
-[
-    protobuf_c_wanted_version=$1
-
-    AC_MSG_CHECKING([for protobuf-c $protobuf_c_wanted_version])
-    AC_MSG_RESULT
-
-    AC_ARG_WITH([protobuf-c],
-        AC_HELP_STRING([--with-protobuf-c=@<:@ARG@:>@],
-            [use protobuf-c library from given prefix (ARG=path); check standard prefixes (ARG=yes); disable (ARG=no)]
-        ),
-        [
-        if test "$withval" = "yes"; then
-            if test -f /usr/local/include/google/protobuf-c/protobuf-c.h ; then
-                protobuf_c_prefix=/usr/local
-            elif test -f /usr/include/google/protobuf-c/protobuf-c.h ; then
-                protobuf_c_prefix=/usr
-            else
-                protobuf_c_prefix=""
-            fi
-            protobuf_c_requested="yes"
-        elif test -d "$withval"; then
-            protobuf_c_prefix="$withval"
-            protobuf_c_requested="yes"
-        else
-            protobuf_c_prefix=""
-            protobuf_c_requested="no"
-        fi
-        ],
-        [
-        dnl Default behavior is implicit yes
-        if test -f /usr/local/include/google/protobuf-c/protobuf-c.h ; then
-            protobuf_c_prefix=/usr/local
-        elif test -f /usr/include/google/protobuf-c/protobuf-c.h ; then
-            protobuf_c_prefix=/usr
-        else
-            protobuf_c_prefix=""
-        fi
-        ]
-    )
-
-    AC_ARG_WITH([protobuf-c-inc],
-        AC_HELP_STRING([--with-protobuf-c-inc=@<:@DIR@:>@],
-            [path to protobuf-c library headers]
-        ),
-        [protobuf_c_include_dir="$withval"],
-        [protobuf_c_include_dir=""]
-    )
-    AC_ARG_WITH([protobuf-c-lib],
-        AC_HELP_STRING([--with-protobuf-c-lib=@<:@ARG@:>@],
-            [link options for protobuf-c library]
-        ),
-        [protobuf_c_lib_flags="$withval"],
-        [protobuf_c_lib_flags=""]
-    )
-
-    PROTOBUF_C_CFLAGS=""
-    PROTOBUF_C_LDFLAGS=""
-    PROTOBUF_C_LIBS=""
-
-    dnl
-    dnl Collect include/lib paths and flags
-    dnl
-    run_protobuf_c_test="no"
-
-    if test -n "$protobuf_c_prefix"; then
-        protobuf_c_include_dir="$protobuf_c_prefix/include"
-        protobuf_c_lib_flags="-L$protobuf_c_prefix/lib"
-        protobuf_c_lib_libs="-lprotobuf-c"
-        run_protobuf_c_test="yes"
-    elif test "$protobuf_c_requested" = "yes"; then
-        if test -n "$protobuf_c_include_dir" -a -n "$protobuf_c_lib_flags" -a -n "$protobuf_c_lib_libs"; then
-            run_protobuf_c_test="yes"
-        fi
-    else
-        run_protobuf_c_test="no"
-    fi
-
-    dnl
-    dnl Check protobuf_c files
-    dnl
-    if test "$run_protobuf_c_test" = "yes"; then
-
-        saved_CPPFLAGS="$CPPFLAGS"
-        CPPFLAGS="$CPPFLAGS -I$protobuf_c_include_dir"
-
-        saved_LDFLAGS="$LDFLAGS"
-        LDFLAGS="$LDFLAGS $protobuf_c_lib_flags"
-
-        saved_LIBS="$LIBS"
-        LIBS="$LIBS $protobuf_c_lib_libs"
-
-        dnl
-        dnl Check protobuf_c headers
-        dnl
-        AC_MSG_CHECKING([for protobuf_c headers in $protobuf_c_include_dir])
-
-        AC_LANG_PUSH([C++])
-        AC_COMPILE_IFELSE([
-            AC_LANG_PROGRAM(
-                [[
-@%:@include <google/protobuf-c/protobuf-c.h>
-                ]],
-                [[]]
-            )],
-            [
-            PROTOBUF_C_CFLAGS="-I$protobuf_c_include_dir"
-            protobuf_c_header_found="yes"
-            AC_MSG_RESULT([found])
-            ],
-            [
-            protobuf_c_header_found="no"
-            AC_MSG_RESULT([not found])
-            ]
-        )
-        AC_LANG_POP([C++])
-
-        dnl
-        dnl Check protobuf_c libraries
-        dnl
-        if test "$protobuf_c_header_found" = "yes"; then
-
-            AC_MSG_CHECKING([for protobuf_c library])
-
-            AC_LANG_PUSH([C++])
-            AC_LINK_IFELSE([
-                AC_LANG_PROGRAM(
-                    [[
-@%:@include <google/protobuf-c/protobuf-c.h>
-                    ]],
-                    [[
-    protobuf_c_service_destroy((ProtobufCService *)NULL);
-                    ]]
-                )],
-                [
-                PROTOBUF_C_LDFLAGS="$protobuf_c_lib_flags"
-                PROTOBUF_C_LIBS="$protobuf_c_lib_libs"
-                protobuf_c_lib_found="yes"
-                AC_MSG_RESULT([found])
-                ],
-                [
-                protobuf_c_lib_found="no"
-                AC_MSG_RESULT([not found])
-                ]
-            )
-            AC_LANG_POP([C++])
-        fi
-
-        CPPFLAGS="$saved_CPPFLAGS"
-        LDFLAGS="$saved_LDFLAGS"
-        LIBS="$saved_LIBS"
-    fi
-
-    protobuf_c_version_ok=yes
-    if test "x$protobuf_c_wanted_version" != "x"
-    then
-      AC_MSG_CHECKING([for protobuf-c version >= $protobuf_c_wanted_version])
-      AC_MSG_RESULT
-
-      dnl protobuf-c does not provide any version information in its header
-      dnl files or from within the library itself, so we have to check
-      dnl for availability of features here for now ...
-
-      dnl protobuf-c 0.14 introduced member 'packed' in ProtobufCFieldDescriptor
-      saved_CFLAGS=$CFLAGS
-      CFLAGS="$CFLAGS $PROTOBUF_C_CFLAGS"
-      AX_COMPARE_VERSION([$protobuf_c_wanted_version], [ge], [0.14],
-         [AC_CHECK_MEMBER([ProtobufCFieldDescriptor.packed],,
-                          [AC_CHECK_MEMBER([ProtobufCFieldDescriptor.flags],,
-                                           [protobuf_c_version_ok="no"],
-                                           [[#include <protobuf-c/protobuf-c.h>]])],
-                          [[#include <google/protobuf-c/protobuf-c.h>]
-         ])
-      ])
-      CFLAGS=$saved_CFLAGS
-      
-      AC_MSG_RESULT([protobuf-c >= $protobuf_c_wanted_version: $protobuf_c_version_ok])
-    fi
-
-
-    AC_MSG_CHECKING([for protobuf-c usability])
-
-    if test "$run_protobuf_c_test" = "yes"; then
-        if test "$protobuf_c_header_found" = "yes" -a "$protobuf_c_lib_found" = "yes" -a "$protobuf_c_version_ok" = "yes"
-        then
-            AC_SUBST([PROTOBUF_C_CFLAGS])
-            AC_SUBST([PROTOBUF_C_LDFLAGS])
-            AC_SUBST([PROTOBUF_C_LIBS])
-            AC_SUBST([HAVE_PROTOBUF_C])
-
-            AC_DEFINE([HAVE_PROTOBUF_C], [1],
-                [Define to 1 if protobuf_c library is available])
-
-            HAVE_PROTOBUF_C="yes"
-	    AC_MSG_RESULT([yes])
-
-	    protoc_path="$protobuf_c_prefix/bin:$PATH"
-	    AC_PATH_PROG(PROTOC_C, protoc-c, false, $protoc_path)
-        else
-            HAVE_PROTOBUF_C="no"
-            AC_MSG_RESULT([no])
-        fi
-
-
-    else
-        HAVE_PROTOBUF_C="no"
-        AC_MSG_RESULT([no])
-
-        if test "$protobuf_c_requested" = "yes"; then
-            AC_MSG_WARN([protobuf-c support requested but headers or library not found. Specify valid prefix of protobuf-c using --with-protobuf-c=@<:@DIR@:>@ or provide include directory and linker flags using --with-protobuf-c-inc and --with-protobuf-c-lib])
-        fi
-    fi
-])
-
-
-
diff --git a/m4/ax_lib_xml2.m4 b/m4/ax_lib_xml2.m4
deleted file mode 100644
index d0cd2cb..0000000
--- a/m4/ax_lib_xml2.m4
+++ /dev/null
@@ -1,150 +0,0 @@
-# SYNOPSIS
-#
-#   AX_LIB_XML2([MINIMUM-VERSION])
-#
-# DESCRIPTION
-#
-#   This macro provides tests of availability of xml2 'libxml2' library
-#   of particular version or newer.
-#
-#   AX_LIB_LIBXML2 macro takes only one argument which is optional. If
-#   there is no required version passed, then macro does not run version
-#   test.
-#
-#   The --with-libxml2 option takes one of three possible values:
-#
-#   no - do not check for xml2 library
-#
-#   yes - do check for xml2 library in standard locations (xml2-config
-#   should be in the PATH)
-#
-#   path - complete path to xml2-config utility, use this option if xml2-config
-#   can't be found in the PATH
-#
-#   This macro calls:
-#
-#     AC_SUBST(XML2_CFLAGS)
-#     AC_SUBST(XML2_LDFLAGS)
-#     AC_SUBST(XML2_VERSION)
-#
-#   And sets:
-#
-#     HAVE_XML2
-#
-# LICENSE
-#
-#   Copyright (c) 2009 Hartmut Holzgraefe <hartmut at php.net>
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved.
-
-AC_DEFUN([AX_LIB_XML2],
-[
-    AC_ARG_WITH([libxml2],
-        AC_HELP_STRING([--with-libxml2=@<:@ARG@:>@],
-            [use libxml2 library @<:@default=yes@:>@, optionally specify path to xml2-config]
-        ),
-        [
-        if test "$withval" = "no"; then
-            want_libxml2="no"
-        elif test "$withval" = "yes"; then
-            want_libxml2="yes"
-        else
-            want_libxml2="yes"
-            XML2_CONFIG="$withval"
-        fi
-        ],
-        [want_libxml2="yes"]
-    )
-
-    XML2_CFLAGS=""
-    XML2_LDFLAGS=""
-    XML2_VERSION=""
-
-    dnl
-    dnl Check xml2 libraries (libxml2)
-    dnl
-
-    if test "$want_libxml2" = "yes"; then
-
-        if test -z "$XML2_CONFIG" -o test; then
-            AC_PATH_PROG([XML2_CONFIG], [xml2-config], [])
-        fi
-
-        if test ! -x "$XML2_CONFIG"; then
-            AC_MSG_ERROR([$XML2_CONFIG does not exist or it is not an exectuable file])
-            XML2_CONFIG="no"
-            found_libxml2="no"
-        fi
-
-        if test "$XML2_CONFIG" != "no"; then
-            AC_MSG_CHECKING([for xml2 libraries])
-
-            XML2_CFLAGS="`$XML2_CONFIG --cflags`"
-            XML2_LDFLAGS="`$XML2_CONFIG --libs`"
-
-            XML2_VERSION=`$XML2_CONFIG --version`
-
-            AC_DEFINE([HAVE_XML2], [1],
-                [Define to 1 if xml2 libraries are available])
-
-            found_libxml2="yes"
-            AC_MSG_RESULT([yes])
-        else
-            found_libxml2="no"
-            AC_MSG_RESULT([no])
-        fi
-    fi
-
-    dnl
-    dnl Check if required version of xml2 is available
-    dnl
-
-
-    libxml2_version_req=ifelse([$1], [], [], [$1])
-
-
-    if test "$found_libxml2" = "yes" -a -n "$libxml2_version_req"; then
-
-        AC_MSG_CHECKING([if libxml2 version is >= $libxml2_version_req])
-
-        dnl Decompose required version string of libxml2
-        dnl and calculate its number representation
-        libxml2_version_req_major=`expr $libxml2_version_req : '\([[0-9]]*\)'`
-        libxml2_version_req_minor=`expr $libxml2_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
-        libxml2_version_req_micro=`expr $libxml2_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
-        if test "x$libxml2_version_req_micro" = "x"; then
-            libxml2_version_req_micro="0"
-        fi
-
-        libxml2_version_req_number=`expr $libxml2_version_req_major \* 1000000 \
-                                   \+ $libxml2_version_req_minor \* 1000 \
-                                   \+ $libxml2_version_req_micro`
-
-        dnl Decompose version string of installed PostgreSQL
-        dnl and calculate its number representation
-        libxml2_version_major=`expr $XML2_VERSION : '\([[0-9]]*\)'`
-        libxml2_version_minor=`expr $XML2_VERSION : '[[0-9]]*\.\([[0-9]]*\)'`
-        libxml2_version_micro=`expr $XML2_VERSION : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
-        if test "x$libxml2_version_micro" = "x"; then
-            libxml2_version_micro="0"
-        fi
-
-        libxml2_version_number=`expr $libxml2_version_major \* 1000000 \
-                                   \+ $libxml2_version_minor \* 1000 \
-                                   \+ $libxml2_version_micro`
-
-        libxml2_version_check=`expr $libxml2_version_number \>\= $libxml2_version_req_number`
-        if test "$libxml2_version_check" = "1"; then
-            AC_MSG_RESULT([yes])
-        else
-            AC_MSG_RESULT([no])
-        fi
-    fi
-
-    AC_SUBST([XML2_VERSION])
-    AC_SUBST([XML2_CFLAGS])
-    AC_SUBST([XML2_LDFLAGS])
-])
-
diff --git a/m4/ax_lib_zlib.m4 b/m4/ax_lib_zlib.m4
deleted file mode 100644
index abb7233..0000000
--- a/m4/ax_lib_zlib.m4
+++ /dev/null
@@ -1,220 +0,0 @@
-# SYNOPSIS
-#
-#   AX_LIB_ZLIB()
-#
-# DESCRIPTION
-#
-#   This macro provides tests of availability of the zlib
-#   compression library. This macro checks for zlib
-#   headers and libraries and defines compilation flags
-#
-#   Macro supports following options and their values:
-#
-#   1) Single-option usage:
-#
-#     --with-zlib      -- yes, no, or path to zlib library 
-#                          installation prefix
-#
-#   2) Three-options usage (all options are required):
-#
-#     --with-zlib=yes
-#     --with-zlib-inc  -- path to base directory with zlib headers
-#     --with-zlib-lib  -- linker flags for zlib
-#
-#   This macro calls:
-#
-#     AC_SUBST(ZLIB_CFLAGS)
-#     AC_SUBST(ZLIB_LDFLAGS)
-#     AC_SUBST(ZLIB_LIBS)
-#
-#   And sets:
-#
-#     HAVE_ZLIB
-#
-# LICENSE
-#
-#   Copyright (c) 2009 Hartmut Holzgraefe <hartmut at php.net>
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved.
-
-AC_DEFUN([AX_LIB_ZLIB],
-[
-    AC_ARG_WITH([zlib],
-        AC_HELP_STRING([--with-zlib=@<:@ARG@:>@],
-            [use zlib library from given prefix (ARG=path); check standard prefixes (ARG=yes); disable (ARG=no)]
-        ),
-        [
-        if test "$withval" = "yes"; then
-            if test -f /usr/local/include/zlib.h ; then
-                zlib_prefix=/usr/local
-            elif test -f /usr/include/zlib.h ; then
-                zlib_prefix=/usr
-            else
-                zlib_prefix=""
-            fi
-            zlib_requested="yes"
-        elif test -d "$withval"; then
-            zlib_prefix="$withval"
-            zlib_requested="yes"
-        else
-            zlib_prefix=""
-            zlib_requested="no"
-        fi
-        ],
-        [
-        dnl Default behavior is implicit yes
-        if test -f /usr/local/include/zlib.h ; then
-            zlib_prefix=/usr/local
-        elif test -f /usr/include/zlib.h ; then
-            zlib_prefix=/usr
-        else
-            zlib_prefix=""
-        fi
-        ]
-    )
-
-    AC_ARG_WITH([zlib-inc],
-        AC_HELP_STRING([--with-zlib-inc=@<:@DIR@:>@],
-            [path to zlib library headers]
-        ),
-        [zlib_include_dir="$withval"],
-        [zlib_include_dir=""]
-    )
-    AC_ARG_WITH([zlib-lib],
-        AC_HELP_STRING([--with-zlib-lib=@<:@ARG@:>@],
-            [link options for zlib library]
-        ),
-        [zlib_lib_flags="$withval"],
-        [zlib_lib_flags=""]
-    )
-
-    ZLIB_CFLAGS=""
-    ZLIB_LDFLAGS=""
-
-    dnl
-    dnl Collect include/lib paths and flags
-    dnl
-    run_zlib_test="no"
-
-    if test -n "$zlib_prefix"; then
-        zlib_include_dir="$zlib_prefix/include"
-        zlib_lib_flags="-L$zlib_prefix/lib"
-        zlib_lib_libs="-lz"
-        run_zlib_test="yes"
-    elif test "$zlib_requested" = "yes"; then
-        if test -n "$zlib_include_dir" -a -n "$zlib_lib_flags" -a -n "$zlib_lib_libs"; then
-            run_zlib_test="yes"
-        fi
-    else
-        run_zlib_test="no"
-    fi
-
-    dnl
-    dnl Check zlib files
-    dnl
-    if test "$run_zlib_test" = "yes"; then
-
-        saved_CPPFLAGS="$CPPFLAGS"
-        CPPFLAGS="$CPPFLAGS -I$zlib_include_dir"
-
-        saved_LDFLAGS="$LDFLAGS"
-        LDFLAGS="$LDFLAGS $zlib_lib_flags"
-
-        saved_LIBS="$LIBS"
-        LIBS="$LIBS $zlib_lib_libs"
-
-        dnl
-        dnl Check zlib headers
-        dnl
-        AC_MSG_CHECKING([for zlib headers in $zlib_include_dir])
-
-        AC_LANG_PUSH([C++])
-        AC_COMPILE_IFELSE([
-            AC_LANG_PROGRAM(
-                [[
-@%:@include <zlib.h>
-                ]],
-                [[]]
-            )],
-            [
-            ZLIB_CFLAGS="-I$zlib_include_dir"
-            zlib_header_found="yes"
-            AC_MSG_RESULT([found])
-            ],
-            [
-            zlib_header_found="no"
-            AC_MSG_RESULT([not found])
-            ]
-        )
-        AC_LANG_POP([C++])
-
-        dnl
-        dnl Check zlib libraries
-        dnl
-        if test "$zlib_header_found" = "yes"; then
-
-            AC_MSG_CHECKING([for zlib library])
-
-            AC_LANG_PUSH([C++])
-            AC_LINK_IFELSE([
-                AC_LANG_PROGRAM(
-                    [[
-@%:@include <zlib.h>
-                    ]],
-                    [[
-    const char *version;
-    
-    version = zlibVersion();
-                    ]]
-                )],
-                [
-                ZLIB_LDFLAGS="$zlib_lib_flags"
-                ZLIB_LIBS="$zlib_lib_libs"
-                zlib_lib_found="yes"
-                AC_MSG_RESULT([found])
-                ],
-                [
-                zlib_lib_found="no"
-                AC_MSG_RESULT([not found])
-                ]
-            )
-            AC_LANG_POP([C++])
-        fi
-
-        CPPFLAGS="$saved_CPPFLAGS"
-        LDFLAGS="$saved_LDFLAGS"
-        LIBS="$saved_LIBS"
-    fi
-
-    AC_MSG_CHECKING([for zlib compression library])
-
-    if test "$run_zlib_test" = "yes"; then
-        if test "$zlib_header_found" = "yes" -a "$zlib_lib_found" = "yes"; then
-            AC_SUBST([ZLIB_CFLAGS])
-            AC_SUBST([ZLIB_LDFLAGS])
-            AC_SUBST([ZLIB_LIBS])
-            AC_SUBST([HAVE_ZLIB])
-
-            AC_DEFINE([HAVE_ZLIB], [1],
-                [Define to 1 if zlib library is available])
-
-            HAVE_ZLIB="yes"
-        else
-            HAVE_ZLIB="no"
-        fi
-
-        AC_MSG_RESULT([$HAVE_ZLIB])
-
-
-    else
-        HAVE_ZLIB="no"
-        AC_MSG_RESULT([$HAVE_ZLIB])
-
-        if test "$zlib_requested" = "yes"; then
-            AC_MSG_WARN([zlib compression support requested but headers or library not found. Specify valid prefix of zlib using --with-zlib=@<:@DIR@:>@ or provide include directory and linker flags using --with-zlib-inc and --with-zlib-lib])
-        fi
-    fi
-])
-
diff --git a/m4/ax_lua.m4 b/m4/ax_lua.m4
deleted file mode 100644
index 8da0a07..0000000
--- a/m4/ax_lua.m4
+++ /dev/null
@@ -1,664 +0,0 @@
-# ===========================================================================
-#          http://www.gnu.org/software/autoconf-archive/ax_lua.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-#   AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
-#   AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
-#   AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
-#   AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
-#
-# DESCRIPTION
-#
-#   Detect a Lua interpreter, optionally specifying a minimum and maximum
-#   version number. Set up important Lua paths, such as the directories in
-#   which to install scripts and modules (shared libraries).
-#
-#   Also detect Lua headers and libraries. The Lua version contained in the
-#   header is checked to match the Lua interpreter version exactly. When
-#   searching for Lua libraries, the version number is used as a suffix.
-#   This is done with the goal of supporting multiple Lua installs (5.1 and
-#   5.2 side-by-side).
-#
-#   A note on compatibility with previous versions: This file has been
-#   mostly rewritten for serial 18. Most developers should be able to use
-#   these macros without needing to modify configure.ac. Care has been taken
-#   to preserve each macro's behavior, but there are some differences:
-#
-#   1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as
-#   AX_PROG_LUA with no arguments.
-#
-#   2) AX_LUA_HEADERS now checks that the version number defined in lua.h
-#   matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore
-#   unnecessary, so it is deprecated and does not expand to anything.
-#
-#   3) The configure flag --with-lua-suffix no longer exists; the user
-#   should instead specify the LUA precious variable on the command line.
-#   See the AX_PROG_LUA description for details.
-#
-#   Please read the macro descriptions below for more information.
-#
-#   This file was inspired by Andrew Dalke's and James Henstridge's
-#   python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4
-#   (serial 17). Basically, this file is a mash-up of those two files. I
-#   like to think it combines the best of the two!
-#
-#   AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua
-#   paths. Adds precious variable LUA, which may contain the path of the Lua
-#   interpreter. If LUA is blank, the user's path is searched for an
-#   suitable interpreter.
-#
-#   If MINIMUM-VERSION is supplied, then only Lua interpreters with a
-#   version number greater or equal to MINIMUM-VERSION will be accepted. If
-#   TOO-BIG-VERSION is also supplied, then only Lua interpreters with a
-#   version number greater or equal to MINIMUM-VERSION and less than
-#   TOO-BIG-VERSION will be accepted.
-#
-#   The Lua version number, LUA_VERSION, is found from the interpreter, and
-#   substituted. LUA_PLATFORM is also found, but not currently supported (no
-#   standard representation).
-#
-#   Finally, the macro finds four paths:
-#
-#     luadir             Directory to install Lua scripts.
-#     pkgluadir          $luadir/$PACKAGE
-#     luaexecdir         Directory to install Lua modules.
-#     pkgluaexecdir      $luaexecdir/$PACKAGE
-#
-#   These paths are found based on $prefix, $exec_prefix, Lua's
-#   package.path, and package.cpath. The first path of package.path
-#   beginning with $prefix is selected as luadir. The first path of
-#   package.cpath beginning with $exec_prefix is used as luaexecdir. This
-#   should work on all reasonable Lua installations. If a path cannot be
-#   determined, a default path is used. Of course, the user can override
-#   these later when invoking make.
-#
-#     luadir             Default: $prefix/share/lua/$LUA_VERSION
-#     luaexecdir         Default: $exec_prefix/lib/lua/$LUA_VERSION
-#
-#   These directories can be used by Automake as install destinations. The
-#   variable name minus 'dir' needs to be used as a prefix to the
-#   appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES.
-#
-#   If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is
-#   performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT-
-#   FOUND is blank, then it will default to printing an error. To prevent
-#   the default behavior, give ':' as an action.
-#
-#   AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be
-#   expanded before this macro. Adds precious variable LUA_INCLUDE, which
-#   may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If
-#   LUA_INCLUDE is blank, then this macro will attempt to find suitable
-#   flags.
-#
-#   LUA_INCLUDE can be used by Automake to compile Lua modules or
-#   executables with embedded interpreters. The *_CPPFLAGS variables should
-#   be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE).
-#
-#   This macro searches for the header lua.h (and others). The search is
-#   performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE.
-#   If the search is unsuccessful, then some common directories are tried.
-#   If the headers are then found, then LUA_INCLUDE is set accordingly.
-#
-#   The paths automatically searched are:
-#
-#     * /usr/include/luaX.Y
-#     * /usr/include/lua/X.Y
-#     * /usr/include/luaXY
-#     * /usr/local/include/luaX.Y
-#     * /usr/local/include/lua-X.Y
-#     * /usr/local/include/lua/X.Y
-#     * /usr/local/include/luaXY
-#
-#   (Where X.Y is the Lua version number, e.g. 5.1.)
-#
-#   The Lua version number found in the headers is always checked to match
-#   the Lua interpreter's version number. Lua headers with mismatched
-#   version numbers are not accepted.
-#
-#   If headers are found, then ACTION-IF-FOUND is performed, otherwise
-#   ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then
-#   it will default to printing an error. To prevent the default behavior,
-#   set the action to ':'.
-#
-#   AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be
-#   expanded before this macro. Adds precious variable LUA_LIB, which may
-#   contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank,
-#   then this macro will attempt to find suitable flags.
-#
-#   LUA_LIB can be used by Automake to link Lua modules or executables with
-#   embedded interpreters. The *_LIBADD and *_LDADD variables should be used
-#   for this purpose, e.g. mymod_LIBADD = $(LUA_LIB).
-#
-#   This macro searches for the Lua library. More technically, it searches
-#   for a library containing the function lua_load. The search is performed
-#   with a combination of LIBS, LIBRARY_PATH, and LUA_LIB.
-#
-#   If the search determines that some linker flags are missing, then those
-#   flags will be added to LUA_LIB.
-#
-#   If libraries are found, then ACTION-IF-FOUND is performed, otherwise
-#   ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then
-#   it will default to printing an error. To prevent the default behavior,
-#   set the action to ':'.
-#
-#   AX_LUA_READLINE: Search for readline headers and libraries. Requires the
-#   AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the
-#   Autoconf Archive.
-#
-#   If a readline compatible library is found, then ACTION-IF-FOUND is
-#   performed, otherwise ACTION-IF-NOT-FOUND is performed.
-#
-# LICENSE
-#
-#   Copyright (c) 2015 Reuben Thomas <rrt at sc3d.org>
-#   Copyright (c) 2014 Tim Perkins <tprk77 at gmail.com>
-#
-#   This program is free software: you can redistribute it and/or modify it
-#   under the terms of the GNU General Public License as published by the
-#   Free Software Foundation, either version 3 of the License, or (at your
-#   option) any later version.
-#
-#   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 for more details.
-#
-#   You should have received a copy of the GNU General Public License along
-#   with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-#   As a special exception, the respective Autoconf Macro's copyright owner
-#   gives unlimited permission to copy, distribute and modify the configure
-#   scripts that are the output of Autoconf when processing the Macro. You
-#   need not follow the terms of the GNU General Public License when using
-#   or distributing such scripts, even though portions of the text of the
-#   Macro appear in them. The GNU General Public License (GPL) does govern
-#   all other use of the material that constitutes the Autoconf Macro.
-#
-#   This special exception to the GPL applies to versions of the Autoconf
-#   Macro released by the Autoconf Archive. When you make and distribute a
-#   modified version of the Autoconf Macro, you may extend this special
-#   exception to the GPL to apply to your modified version as well.
-
-#serial 38
-
-dnl =========================================================================
-dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION],
-dnl             [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-dnl =========================================================================
-AC_DEFUN([AX_PROG_LUA],
-[
-  dnl Check for required tools.
-  AC_REQUIRE([AC_PROG_GREP])
-  AC_REQUIRE([AC_PROG_SED])
-
-  dnl Make LUA a precious variable.
-  AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1])
-
-  dnl Find a Lua interpreter.
-  m4_define_default([_AX_LUA_INTERPRETER_LIST],
-    [lua lua5.2 lua52 lua5.1 lua51 lua50])
-
-  m4_if([$1], [],
-  [ dnl No version check is needed. Find any Lua interpreter.
-    AS_IF([test "x$LUA" = 'x'],
-      [AC_PATH_PROGS([LUA], [_AX_LUA_INTERPRETER_LIST], [:])])
-    ax_display_LUA='lua'
-
-    AS_IF([test "x$LUA" != 'x:'],
-      [ dnl At least check if this is a Lua interpreter.
-        AC_MSG_CHECKING([if $LUA is a Lua interpreter])
-        _AX_LUA_CHK_IS_INTRP([$LUA],
-          [AC_MSG_RESULT([yes])],
-          [ AC_MSG_RESULT([no])
-            AC_MSG_ERROR([not a Lua interpreter])
-          ])
-      ])
-  ],
-  [ dnl A version check is needed.
-    AS_IF([test "x$LUA" != 'x'],
-    [ dnl Check if this is a Lua interpreter.
-      AC_MSG_CHECKING([if $LUA is a Lua interpreter])
-      _AX_LUA_CHK_IS_INTRP([$LUA],
-        [AC_MSG_RESULT([yes])],
-        [ AC_MSG_RESULT([no])
-          AC_MSG_ERROR([not a Lua interpreter])
-        ])
-      dnl Check the version.
-      m4_if([$2], [],
-        [_ax_check_text="whether $LUA version >= $1"],
-        [_ax_check_text="whether $LUA version >= $1, < $2"])
-      AC_MSG_CHECKING([$_ax_check_text])
-      _AX_LUA_CHK_VER([$LUA], [$1], [$2],
-        [AC_MSG_RESULT([yes])],
-        [ AC_MSG_RESULT([no])
-          AC_MSG_ERROR([version is out of range for specified LUA])])
-      ax_display_LUA=$LUA
-    ],
-    [ dnl Try each interpreter until we find one that satisfies VERSION.
-      m4_if([$2], [],
-        [_ax_check_text="for a Lua interpreter with version >= $1"],
-        [_ax_check_text="for a Lua interpreter with version >= $1, < $2"])
-      AC_CACHE_CHECK([$_ax_check_text],
-        [ax_cv_pathless_LUA],
-        [ for ax_cv_pathless_LUA in _AX_LUA_INTERPRETER_LIST none; do
-            test "x$ax_cv_pathless_LUA" = 'xnone' && break
-            _AX_LUA_CHK_IS_INTRP([$ax_cv_pathless_LUA], [], [continue])
-            _AX_LUA_CHK_VER([$ax_cv_pathless_LUA], [$1], [$2], [break])
-          done
-        ])
-      dnl Set $LUA to the absolute path of $ax_cv_pathless_LUA.
-      AS_IF([test "x$ax_cv_pathless_LUA" = 'xnone'],
-        [LUA=':'],
-        [AC_PATH_PROG([LUA], [$ax_cv_pathless_LUA])])
-      ax_display_LUA=$ax_cv_pathless_LUA
-    ])
-  ])
-
-  AS_IF([test "x$LUA" = 'x:'],
-  [ dnl Run any user-specified action, or abort.
-    m4_default([$4], [AC_MSG_ERROR([cannot find suitable Lua interpreter])])
-  ],
-  [ dnl Query Lua for its version number.
-    AC_CACHE_CHECK([for $ax_display_LUA version],
-      [ax_cv_lua_version],
-      [ dnl Get the interpreter version in X.Y format. This should work for
-        dnl interpreters version 5.0 and beyond.
-        ax_cv_lua_version=[`$LUA -e '
-          -- return a version number in X.Y format
-          local _, _, ver = string.find(_VERSION, "^Lua (%d+%.%d+)")
-          print(ver)'`]
-      ])
-    AS_IF([test "x$ax_cv_lua_version" = 'x'],
-      [AC_MSG_ERROR([invalid Lua version number])])
-    AC_SUBST([LUA_VERSION], [$ax_cv_lua_version])
-    AC_SUBST([LUA_SHORT_VERSION], [`echo "$LUA_VERSION" | $SED 's|\.||'`])
-
-    dnl The following check is not supported:
-    dnl At times (like when building shared libraries) you may want to know
-    dnl which OS platform Lua thinks this is.
-    AC_CACHE_CHECK([for $ax_display_LUA platform],
-      [ax_cv_lua_platform],
-      [ax_cv_lua_platform=[`$LUA -e 'print("unknown")'`]])
-    AC_SUBST([LUA_PLATFORM], [$ax_cv_lua_platform])
-
-    dnl Use the values of $prefix and $exec_prefix for the corresponding
-    dnl values of LUA_PREFIX and LUA_EXEC_PREFIX. These are made distinct
-    dnl variables so they can be overridden if need be. However, the general
-    dnl consensus is that you shouldn't need this ability.
-    AC_SUBST([LUA_PREFIX], ['${prefix}'])
-    AC_SUBST([LUA_EXEC_PREFIX], ['${exec_prefix}'])
-
-    dnl Lua provides no way to query the script directory, and instead
-    dnl provides LUA_PATH. However, we should be able to make a safe educated
-    dnl guess. If the built-in search path contains a directory which is
-    dnl prefixed by $prefix, then we can store scripts there. The first
-    dnl matching path will be used.
-    AC_CACHE_CHECK([for $ax_display_LUA script directory],
-      [ax_cv_lua_luadir],
-      [ AS_IF([test "x$prefix" = 'xNONE'],
-          [ax_lua_prefix=$ac_default_prefix],
-          [ax_lua_prefix=$prefix])
-
-        dnl Initialize to the default path.
-        ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION"
-
-        dnl Try to find a path with the prefix.
-        _AX_LUA_FND_PRFX_PTH([$LUA], [$ax_lua_prefix], [script])
-        AS_IF([test "x$ax_lua_prefixed_path" != 'x'],
-        [ dnl Fix the prefix.
-          _ax_strip_prefix=`echo "$ax_lua_prefix" | $SED 's|.|.|g'`
-          ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \
-            $SED "s|^$_ax_strip_prefix|$LUA_PREFIX|"`
-        ])
-      ])
-    AC_SUBST([luadir], [$ax_cv_lua_luadir])
-    AC_SUBST([pkgluadir], [\${luadir}/$PACKAGE])
-
-    dnl Lua provides no way to query the module directory, and instead
-    dnl provides LUA_PATH. However, we should be able to make a safe educated
-    dnl guess. If the built-in search path contains a directory which is
-    dnl prefixed by $exec_prefix, then we can store modules there. The first
-    dnl matching path will be used.
-    AC_CACHE_CHECK([for $ax_display_LUA module directory],
-      [ax_cv_lua_luaexecdir],
-      [ AS_IF([test "x$exec_prefix" = 'xNONE'],
-          [ax_lua_exec_prefix=$ax_lua_prefix],
-          [ax_lua_exec_prefix=$exec_prefix])
-
-        dnl Initialize to the default path.
-        ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION"
-
-        dnl Try to find a path with the prefix.
-        _AX_LUA_FND_PRFX_PTH([$LUA],
-          [$ax_lua_exec_prefix], [module])
-        AS_IF([test "x$ax_lua_prefixed_path" != 'x'],
-        [ dnl Fix the prefix.
-          _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | $SED 's|.|.|g'`
-          ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \
-            $SED "s|^$_ax_strip_prefix|$LUA_EXEC_PREFIX|"`
-        ])
-      ])
-    AC_SUBST([luaexecdir], [$ax_cv_lua_luaexecdir])
-    AC_SUBST([pkgluaexecdir], [\${luaexecdir}/$PACKAGE])
-
-    dnl Run any user specified action.
-    $3
-  ])
-])
-
-dnl AX_WITH_LUA is now the same thing as AX_PROG_LUA.
-AC_DEFUN([AX_WITH_LUA],
-[
-  AC_MSG_WARN([[$0 is deprecated, please use AX_PROG_LUA instead]])
-  AX_PROG_LUA
-])
-
-
-dnl =========================================================================
-dnl _AX_LUA_CHK_IS_INTRP(PROG, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
-dnl =========================================================================
-AC_DEFUN([_AX_LUA_CHK_IS_INTRP],
-[
-  dnl A minimal Lua factorial to prove this is an interpreter. This should work
-  dnl for Lua interpreters version 5.0 and beyond.
-  _ax_lua_factorial=[`$1 2>/dev/null -e '
-    -- a simple factorial
-    function fact (n)
-      if n == 0 then
-        return 1
-      else
-        return n * fact(n-1)
-      end
-    end
-    print("fact(5) is " .. fact(5))'`]
-  AS_IF([test "$_ax_lua_factorial" = 'fact(5) is 120'],
-    [$2], [$3])
-])
-
-
-dnl =========================================================================
-dnl _AX_LUA_CHK_VER(PROG, MINIMUM-VERSION, [TOO-BIG-VERSION],
-dnl                 [ACTION-IF-TRUE], [ACTION-IF-FALSE])
-dnl =========================================================================
-AC_DEFUN([_AX_LUA_CHK_VER],
-[
-  dnl Check that the Lua version is within the bounds. Only the major and minor
-  dnl version numbers are considered. This should work for Lua interpreters
-  dnl version 5.0 and beyond.
-  _ax_lua_good_version=[`$1 -e '
-    -- a script to compare versions
-    function verstr2num(verstr)
-      local _, _, majorver, minorver = string.find(verstr, "^(%d+)%.(%d+)")
-      if majorver and minorver then
-        return tonumber(majorver) * 100 + tonumber(minorver)
-      end
-    end
-    local minver = verstr2num("$2")
-    local _, _, trimver = string.find(_VERSION, "^Lua (.*)")
-    local ver = verstr2num(trimver)
-    local maxver = verstr2num("$3") or 1e9
-    if minver <= ver and ver < maxver then
-      print("yes")
-    else
-      print("no")
-    end'`]
-    AS_IF([test "x$_ax_lua_good_version" = "xyes"],
-      [$4], [$5])
-])
-
-
-dnl =========================================================================
-dnl _AX_LUA_FND_PRFX_PTH(PROG, PREFIX, SCRIPT-OR-MODULE-DIR)
-dnl =========================================================================
-AC_DEFUN([_AX_LUA_FND_PRFX_PTH],
-[
-  dnl Get the script or module directory by querying the Lua interpreter,
-  dnl filtering on the given prefix, and selecting the shallowest path. If no
-  dnl path is found matching the prefix, the result will be an empty string.
-  dnl The third argument determines the type of search, it can be 'script' or
-  dnl 'module'. Supplying 'script' will perform the search with package.path
-  dnl and LUA_PATH, and supplying 'module' will search with package.cpath and
-  dnl LUA_CPATH. This is done for compatibility with Lua 5.0.
-
-  ax_lua_prefixed_path=[`$1 -e '
-    -- get the path based on search type
-    local searchtype = "$3"
-    local paths = ""
-    if searchtype == "script" then
-      paths = (package and package.path) or LUA_PATH
-    elseif searchtype == "module" then
-      paths = (package and package.cpath) or LUA_CPATH
-    end
-    -- search for the prefix
-    local prefix = "'$2'"
-    local minpath = ""
-    local mindepth = 1e9
-    string.gsub(paths, "(@<:@^;@:>@+)",
-      function (path)
-        path = string.gsub(path, "%?.*$", "")
-        path = string.gsub(path, "/@<:@^/@:>@*$", "")
-        if string.find(path, prefix) then
-          local depth = string.len(string.gsub(path, "@<:@^/@:>@", ""))
-          if depth < mindepth then
-            minpath = path
-            mindepth = depth
-          end
-        end
-      end)
-    print(minpath)'`]
-])
-
-
-dnl =========================================================================
-dnl AX_LUA_HEADERS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-dnl =========================================================================
-AC_DEFUN([AX_LUA_HEADERS],
-[
-  dnl Check for LUA_VERSION.
-  AC_MSG_CHECKING([if LUA_VERSION is defined])
-  AS_IF([test "x$LUA_VERSION" != 'x'],
-    [AC_MSG_RESULT([yes])],
-    [ AC_MSG_RESULT([no])
-      AC_MSG_ERROR([cannot check Lua headers without knowing LUA_VERSION])
-    ])
-
-  dnl Make LUA_INCLUDE a precious variable.
-  AC_ARG_VAR([LUA_INCLUDE], [The Lua includes, e.g. -I/usr/include/lua5.1])
-
-  dnl Some default directories to search.
-  LUA_SHORT_VERSION=`echo "$LUA_VERSION" | $SED 's|\.||'`
-  m4_define_default([_AX_LUA_INCLUDE_LIST],
-    [ /usr/include/lua$LUA_VERSION \
-      /usr/include/lua-$LUA_VERSION \
-      /usr/include/lua/$LUA_VERSION \
-      /usr/include/lua$LUA_SHORT_VERSION \
-      /usr/local/include/lua$LUA_VERSION \
-      /usr/local/include/lua-$LUA_VERSION \
-      /usr/local/include/lua/$LUA_VERSION \
-      /usr/local/include/lua$LUA_SHORT_VERSION \
-    ])
-
-  dnl Try to find the headers.
-  _ax_lua_saved_cppflags=$CPPFLAGS
-  CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
-  AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
-  CPPFLAGS=$_ax_lua_saved_cppflags
-
-  dnl Try some other directories if LUA_INCLUDE was not set.
-  AS_IF([test "x$LUA_INCLUDE" = 'x' &&
-         test "x$ac_cv_header_lua_h" != 'xyes'],
-    [ dnl Try some common include paths.
-      for _ax_include_path in _AX_LUA_INCLUDE_LIST; do
-        test ! -d "$_ax_include_path" && continue
-
-        AC_MSG_CHECKING([for Lua headers in])
-        AC_MSG_RESULT([$_ax_include_path])
-
-        AS_UNSET([ac_cv_header_lua_h])
-        AS_UNSET([ac_cv_header_lualib_h])
-        AS_UNSET([ac_cv_header_lauxlib_h])
-        AS_UNSET([ac_cv_header_luaconf_h])
-
-        _ax_lua_saved_cppflags=$CPPFLAGS
-        CPPFLAGS="$CPPFLAGS -I$_ax_include_path"
-        AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
-        CPPFLAGS=$_ax_lua_saved_cppflags
-
-        AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'],
-          [ LUA_INCLUDE="-I$_ax_include_path"
-            break
-          ])
-      done
-    ])
-
-  AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'],
-    [ dnl Make a program to print LUA_VERSION defined in the header.
-      dnl TODO It would be really nice if we could do this without compiling a
-      dnl program, then it would work when cross compiling. But I'm not sure how
-      dnl to do this reliably. For now, assume versions match when cross compiling.
-
-      AS_IF([test "x$cross_compiling" != 'xyes'],
-        [ AC_CACHE_CHECK([for Lua header version],
-            [ax_cv_lua_header_version],
-            [ _ax_lua_saved_cppflags=$CPPFLAGS
-              CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
-              AC_RUN_IFELSE(
-                [ AC_LANG_SOURCE([[
-#include <lua.h>
-#include <stdlib.h>
-#include <stdio.h>
-int main(int argc, char ** argv)
-{
-  if(argc > 1) printf("%s", LUA_VERSION);
-  exit(EXIT_SUCCESS);
-}
-]])
-                ],
-                [ ax_cv_lua_header_version=`./conftest$EXEEXT p | \
-                    $SED -n "s|^Lua \(@<:@0-9@:>@\{1,\}\.@<:@0-9@:>@\{1,\}\).\{0,\}|\1|p"`
-                ],
-                [ax_cv_lua_header_version='unknown'])
-              CPPFLAGS=$_ax_lua_saved_cppflags
-            ])
-
-          dnl Compare this to the previously found LUA_VERSION.
-          AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION])
-          AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"],
-            [ AC_MSG_RESULT([yes])
-              ax_header_version_match='yes'
-            ],
-            [ AC_MSG_RESULT([no])
-              ax_header_version_match='no'
-            ])
-        ],
-        [ AC_MSG_WARN([cross compiling so assuming header version number matches])
-          ax_header_version_match='yes'
-        ])
-    ])
-
-  dnl Was LUA_INCLUDE specified?
-  AS_IF([test "x$ax_header_version_match" != 'xyes' &&
-         test "x$LUA_INCLUDE" != 'x'],
-    [AC_MSG_ERROR([cannot find headers for specified LUA_INCLUDE])])
-
-  dnl Test the final result and run user code.
-  AS_IF([test "x$ax_header_version_match" = 'xyes'], [$1],
-    [m4_default([$2], [AC_MSG_ERROR([cannot find Lua includes])])])
-])
-
-dnl AX_LUA_HEADERS_VERSION no longer exists, use AX_LUA_HEADERS.
-AC_DEFUN([AX_LUA_HEADERS_VERSION],
-[
-  AC_MSG_WARN([[$0 is deprecated, please use AX_LUA_HEADERS instead]])
-])
-
-
-dnl =========================================================================
-dnl AX_LUA_LIBS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-dnl =========================================================================
-AC_DEFUN([AX_LUA_LIBS],
-[
-  dnl TODO Should this macro also check various -L flags?
-
-  dnl Check for LUA_VERSION.
-  AC_MSG_CHECKING([if LUA_VERSION is defined])
-  AS_IF([test "x$LUA_VERSION" != 'x'],
-    [AC_MSG_RESULT([yes])],
-    [ AC_MSG_RESULT([no])
-      AC_MSG_ERROR([cannot check Lua libs without knowing LUA_VERSION])
-    ])
-
-  dnl Make LUA_LIB a precious variable.
-  AC_ARG_VAR([LUA_LIB], [The Lua library, e.g. -llua5.1])
-
-  AS_IF([test "x$LUA_LIB" != 'x'],
-  [ dnl Check that LUA_LIBS works.
-    _ax_lua_saved_libs=$LIBS
-    LIBS="$LIBS $LUA_LIB"
-    AC_SEARCH_LIBS([lua_load], [],
-      [_ax_found_lua_libs='yes'],
-      [_ax_found_lua_libs='no'])
-    LIBS=$_ax_lua_saved_libs
-
-    dnl Check the result.
-    AS_IF([test "x$_ax_found_lua_libs" != 'xyes'],
-      [AC_MSG_ERROR([cannot find libs for specified LUA_LIB])])
-  ],
-  [ dnl First search for extra libs.
-    _ax_lua_extra_libs=''
-
-    _ax_lua_saved_libs=$LIBS
-    LIBS="$LIBS $LUA_LIB"
-    AC_SEARCH_LIBS([exp], [m])
-    AC_SEARCH_LIBS([dlopen], [dl])
-    LIBS=$_ax_lua_saved_libs
-
-    AS_IF([test "x$ac_cv_search_exp" != 'xno' &&
-           test "x$ac_cv_search_exp" != 'xnone required'],
-      [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp"])
-
-    AS_IF([test "x$ac_cv_search_dlopen" != 'xno' &&
-           test "x$ac_cv_search_dlopen" != 'xnone required'],
-      [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen"])
-
-    dnl Try to find the Lua libs.
-    _ax_lua_saved_libs=$LIBS
-    LIBS="$LIBS $LUA_LIB"
-    AC_SEARCH_LIBS([lua_load],
-      [ lua$LUA_VERSION \
-        lua$LUA_SHORT_VERSION \
-        lua-$LUA_VERSION \
-        lua-$LUA_SHORT_VERSION \
-        lua \
-      ],
-      [_ax_found_lua_libs='yes'],
-      [_ax_found_lua_libs='no'],
-      [$_ax_lua_extra_libs])
-    LIBS=$_ax_lua_saved_libs
-
-    AS_IF([test "x$ac_cv_search_lua_load" != 'xno' &&
-           test "x$ac_cv_search_lua_load" != 'xnone required'],
-      [LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs"])
-  ])
-
-  dnl Test the result and run user code.
-  AS_IF([test "x$_ax_found_lua_libs" = 'xyes'], [$1],
-    [m4_default([$2], [AC_MSG_ERROR([cannot find Lua libs])])])
-])
-
-
-dnl =========================================================================
-dnl AX_LUA_READLINE([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-dnl =========================================================================
-AC_DEFUN([AX_LUA_READLINE],
-[
-  AX_LIB_READLINE
-  AS_IF([test "x$ac_cv_header_readline_readline_h" != 'x' &&
-         test "x$ac_cv_header_readline_history_h" != 'x'],
-    [ LUA_LIBS_CFLAGS="-DLUA_USE_READLINE $LUA_LIBS_CFLAGS"
-      $1
-    ],
-    [$2])
-])
diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4
deleted file mode 100644
index d383ad5..0000000
--- a/m4/ax_pthread.m4
+++ /dev/null
@@ -1,332 +0,0 @@
-# ===========================================================================
-#        http://www.gnu.org/software/autoconf-archive/ax_pthread.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-#   AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
-#
-# DESCRIPTION
-#
-#   This macro figures out how to build C programs using POSIX threads. It
-#   sets the PTHREAD_LIBS output variable to the threads library and linker
-#   flags, and the PTHREAD_CFLAGS output variable to any special C compiler
-#   flags that are needed. (The user can also force certain compiler
-#   flags/libs to be tested by setting these environment variables.)
-#
-#   Also sets PTHREAD_CC to any special C compiler that is needed for
-#   multi-threaded programs (defaults to the value of CC otherwise). (This
-#   is necessary on AIX to use the special cc_r compiler alias.)
-#
-#   NOTE: You are assumed to not only compile your program with these flags,
-#   but also link it with them as well. e.g. you should link with
-#   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
-#
-#   If you are only building threads programs, you may wish to use these
-#   variables in your default LIBS, CFLAGS, and CC:
-#
-#     LIBS="$PTHREAD_LIBS $LIBS"
-#     CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
-#     CC="$PTHREAD_CC"
-#
-#   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
-#   has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
-#   (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
-#
-#   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
-#   PTHREAD_PRIO_INHERIT symbol is defined when compiling with
-#   PTHREAD_CFLAGS.
-#
-#   ACTION-IF-FOUND is a list of shell commands to run if a threads library
-#   is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
-#   is not found. If ACTION-IF-FOUND is not specified, the default action
-#   will define HAVE_PTHREAD.
-#
-#   Please let the authors know if this macro fails on any platform, or if
-#   you have any other suggestions or comments. This macro was based on work
-#   by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
-#   from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
-#   Alejandro Forero Cuervo to the autoconf macro repository. We are also
-#   grateful for the helpful feedback of numerous users.
-#
-#   Updated for Autoconf 2.68 by Daniel Richard G.
-#
-# LICENSE
-#
-#   Copyright (c) 2008 Steven G. Johnson <stevenj at alum.mit.edu>
-#   Copyright (c) 2011 Daniel Richard G. <skunk at iSKUNK.ORG>
-#
-#   This program is free software: you can redistribute it and/or modify it
-#   under the terms of the GNU General Public License as published by the
-#   Free Software Foundation, either version 3 of the License, or (at your
-#   option) any later version.
-#
-#   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 for more details.
-#
-#   You should have received a copy of the GNU General Public License along
-#   with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-#   As a special exception, the respective Autoconf Macro's copyright owner
-#   gives unlimited permission to copy, distribute and modify the configure
-#   scripts that are the output of Autoconf when processing the Macro. You
-#   need not follow the terms of the GNU General Public License when using
-#   or distributing such scripts, even though portions of the text of the
-#   Macro appear in them. The GNU General Public License (GPL) does govern
-#   all other use of the material that constitutes the Autoconf Macro.
-#
-#   This special exception to the GPL applies to versions of the Autoconf
-#   Macro released by the Autoconf Archive. When you make and distribute a
-#   modified version of the Autoconf Macro, you may extend this special
-#   exception to the GPL to apply to your modified version as well.
-
-#serial 21
-
-AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
-AC_DEFUN([AX_PTHREAD], [
-AC_REQUIRE([AC_CANONICAL_HOST])
-AC_LANG_PUSH([C])
-ax_pthread_ok=no
-
-# We used to check for pthread.h first, but this fails if pthread.h
-# requires special compiler flags (e.g. on True64 or Sequent).
-# It gets checked for in the link test anyway.
-
-# First of all, check if the user has set any of the PTHREAD_LIBS,
-# etcetera environment variables, and if threads linking works using
-# them:
-if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
-        save_CFLAGS="$CFLAGS"
-        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
-        save_LIBS="$LIBS"
-        LIBS="$PTHREAD_LIBS $LIBS"
-        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
-        AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
-        AC_MSG_RESULT([$ax_pthread_ok])
-        if test x"$ax_pthread_ok" = xno; then
-                PTHREAD_LIBS=""
-                PTHREAD_CFLAGS=""
-        fi
-        LIBS="$save_LIBS"
-        CFLAGS="$save_CFLAGS"
-fi
-
-# We must check for the threads library under a number of different
-# names; the ordering is very important because some systems
-# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
-# libraries is broken (non-POSIX).
-
-# Create a list of thread flags to try.  Items starting with a "-" are
-# C compiler flags, and other items are library names, except for "none"
-# which indicates that we try without any flags at all, and "pthread-config"
-# which is a program returning the flags for the Pth emulation library.
-
-ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
-
-# The ordering *is* (sometimes) important.  Some notes on the
-# individual items follow:
-
-# pthreads: AIX (must check this before -lpthread)
-# none: in case threads are in libc; should be tried before -Kthread and
-#       other compiler flags to prevent continual compiler warnings
-# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
-# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
-# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
-# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
-# -pthreads: Solaris/gcc
-# -mthreads: Mingw32/gcc, Lynx/gcc
-# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
-#      doesn't hurt to check since this sometimes defines pthreads too;
-#      also defines -D_REENTRANT)
-#      ... -mt is also the pthreads flag for HP/aCC
-# pthread: Linux, etcetera
-# --thread-safe: KAI C++
-# pthread-config: use pthread-config program (for GNU Pth library)
-
-case ${host_os} in
-        solaris*)
-
-        # On Solaris (at least, for some versions), libc contains stubbed
-        # (non-functional) versions of the pthreads routines, so link-based
-        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
-        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
-        # a function called by this macro, so we could check for that, but
-        # who knows whether they'll stub that too in a future libc.)  So,
-        # we'll just look for -pthreads and -lpthread first:
-
-        ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
-        ;;
-
-        darwin*)
-        ax_pthread_flags="-pthread $ax_pthread_flags"
-        ;;
-esac
-
-# Clang doesn't consider unrecognized options an error unless we specify
-# -Werror. We throw in some extra Clang-specific options to ensure that
-# this doesn't happen for GCC, which also accepts -Werror.
-
-AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
-save_CFLAGS="$CFLAGS"
-ax_pthread_extra_flags="-Werror"
-CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
-                  [AC_MSG_RESULT([yes])],
-                  [ax_pthread_extra_flags=
-                   AC_MSG_RESULT([no])])
-CFLAGS="$save_CFLAGS"
-
-if test x"$ax_pthread_ok" = xno; then
-for flag in $ax_pthread_flags; do
-
-        case $flag in
-                none)
-                AC_MSG_CHECKING([whether pthreads work without any flags])
-                ;;
-
-                -*)
-                AC_MSG_CHECKING([whether pthreads work with $flag])
-                PTHREAD_CFLAGS="$flag"
-                ;;
-
-                pthread-config)
-                AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
-                if test x"$ax_pthread_config" = xno; then continue; fi
-                PTHREAD_CFLAGS="`pthread-config --cflags`"
-                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
-                ;;
-
-                *)
-                AC_MSG_CHECKING([for the pthreads library -l$flag])
-                PTHREAD_LIBS="-l$flag"
-                ;;
-        esac
-
-        save_LIBS="$LIBS"
-        save_CFLAGS="$CFLAGS"
-        LIBS="$PTHREAD_LIBS $LIBS"
-        CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
-
-        # Check for various functions.  We must include pthread.h,
-        # since some functions may be macros.  (On the Sequent, we
-        # need a special flag -Kthread to make this header compile.)
-        # We check for pthread_join because it is in -lpthread on IRIX
-        # while pthread_create is in libc.  We check for pthread_attr_init
-        # due to DEC craziness with -lpthreads.  We check for
-        # pthread_cleanup_push because it is one of the few pthread
-        # functions on Solaris that doesn't have a non-functional libc stub.
-        # We try pthread_create on general principles.
-        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
-                        static void routine(void *a) { a = 0; }
-                        static void *start_routine(void *a) { return a; }],
-                       [pthread_t th; pthread_attr_t attr;
-                        pthread_create(&th, 0, start_routine, 0);
-                        pthread_join(th, 0);
-                        pthread_attr_init(&attr);
-                        pthread_cleanup_push(routine, 0);
-                        pthread_cleanup_pop(0) /* ; */])],
-                [ax_pthread_ok=yes],
-                [])
-
-        LIBS="$save_LIBS"
-        CFLAGS="$save_CFLAGS"
-
-        AC_MSG_RESULT([$ax_pthread_ok])
-        if test "x$ax_pthread_ok" = xyes; then
-                break;
-        fi
-
-        PTHREAD_LIBS=""
-        PTHREAD_CFLAGS=""
-done
-fi
-
-# Various other checks:
-if test "x$ax_pthread_ok" = xyes; then
-        save_LIBS="$LIBS"
-        LIBS="$PTHREAD_LIBS $LIBS"
-        save_CFLAGS="$CFLAGS"
-        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
-
-        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
-        AC_MSG_CHECKING([for joinable pthread attribute])
-        attr_name=unknown
-        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
-            AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
-                           [int attr = $attr; return attr /* ; */])],
-                [attr_name=$attr; break],
-                [])
-        done
-        AC_MSG_RESULT([$attr_name])
-        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
-            AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
-                               [Define to necessary symbol if this constant
-                                uses a non-standard name on your system.])
-        fi
-
-        AC_MSG_CHECKING([if more special flags are required for pthreads])
-        flag=no
-        case ${host_os} in
-            aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
-            osf* | hpux*) flag="-D_REENTRANT";;
-            solaris*)
-            if test "$GCC" = "yes"; then
-                flag="-D_REENTRANT"
-            else
-                # TODO: What about Clang on Solaris?
-                flag="-mt -D_REENTRANT"
-            fi
-            ;;
-        esac
-        AC_MSG_RESULT([$flag])
-        if test "x$flag" != xno; then
-            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
-        fi
-
-        AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
-            [ax_cv_PTHREAD_PRIO_INHERIT], [
-                AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
-                                                [[int i = PTHREAD_PRIO_INHERIT;]])],
-                    [ax_cv_PTHREAD_PRIO_INHERIT=yes],
-                    [ax_cv_PTHREAD_PRIO_INHERIT=no])
-            ])
-        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
-            [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
-
-        LIBS="$save_LIBS"
-        CFLAGS="$save_CFLAGS"
-
-        # More AIX lossage: compile with *_r variant
-        if test "x$GCC" != xyes; then
-            case $host_os in
-                aix*)
-                AS_CASE(["x/$CC"],
-                  [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
-                  [#handle absolute path differently from PATH based program lookup
-                   AS_CASE(["x$CC"],
-                     [x/*],
-                     [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
-                     [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
-                ;;
-            esac
-        fi
-fi
-
-test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
-
-AC_SUBST([PTHREAD_LIBS])
-AC_SUBST([PTHREAD_CFLAGS])
-AC_SUBST([PTHREAD_CC])
-
-# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
-if test x"$ax_pthread_ok" = xyes; then
-        ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
-        :
-else
-        ax_pthread_ok=no
-        $2
-fi
-AC_LANG_POP
-])dnl AX_PTHREAD
diff --git a/middle-pgsql.cpp b/middle-pgsql.cpp
index ab198e7..cb34623 100644
--- a/middle-pgsql.cpp
+++ b/middle-pgsql.cpp
@@ -8,10 +8,6 @@
 
 #include "config.h"
 
-#ifdef HAVE_PTHREAD
-#include <pthread.h>
-#endif
-
 #ifdef HAVE_SYS_WAIT_H
 #include <sys/wait.h>
 #endif
@@ -33,27 +29,28 @@ using namespace std;
 #define alloca _alloca
 #endif
 
-#include <libpq-fe.h>
-
-#include "osmtypes.hpp"
-#include "middle-pgsql.hpp"
-#include "output-pgsql.hpp"
-#include "options.hpp"
-#include "node-ram-cache.hpp"
-#include "node-persistent-cache.hpp"
-#include "pgsql.hpp"
-#include "util.hpp"
-
 #include <stdexcept>
-#include <algorithm>
+#include <unordered_map>
+
 #include <cassert>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
 #include <ctime>
+#include <future>
+
 #include <boost/format.hpp>
-#include <boost/foreach.hpp>
-#include <boost/unordered_map.hpp>
+
+#include <libpq-fe.h>
+
+#include "middle-pgsql.hpp"
+#include "node-persistent-cache.hpp"
+#include "node-ram-cache.hpp"
+#include "options.hpp"
+#include "osmtypes.hpp"
+#include "output-pgsql.hpp"
+#include "pgsql.hpp"
+#include "util.hpp"
 
 enum table_id {
     t_node, t_way, t_rel
@@ -81,7 +78,7 @@ middle_pgsql_t::table_desc::table_desc(const char *name_,
       array_indexes(array_indexes_),
       copyMode(0),
       transactionMode(0),
-      sql_conn(NULL)
+      sql_conn(nullptr)
 {}
 
 #define HELPER_STATE_UNINITIALIZED -1
@@ -131,7 +128,7 @@ _restart:
 // Special escape routine for escaping strings in array constants: double quote, backslash,newline, tab*/
 inline char *escape_tag( char *ptr, const std::string &in, bool escape )
 {
-  BOOST_FOREACH(const char c, in)
+  for (const char c: in)
   {
     switch(c)
     {
@@ -169,7 +166,7 @@ inline char *escape_tag( char *ptr, const std::string &in, bool escape )
   return ptr;
 }
 
-// escape means we return '\N' for copy mode, otherwise we return just NULL */
+// escape means we return '\N' for copy mode, otherwise we return just nullptr */
 const char *pgsql_store_tags(const taglist_t &tags, bool escape)
 {
   static char *buffer;
@@ -181,7 +178,7 @@ const char *pgsql_store_tags(const taglist_t &tags, bool escape)
     if( escape )
       return "\\N";
     else
-      return NULL;
+      return nullptr;
   }
 
   if( buflen <= countlist * 24 ) // LE so 0 always matches */
@@ -267,7 +264,7 @@ void pgsql_parse_tags(const char *string, taglist_t &tags)
     string++;
     string = decode_upto( string, val );
     // String points to the comma or closing '}' */
-    tags.push_back(tag(key, val));
+    tags.push_back(tag_t(key, val));
     if( *string == ',' )
       string++;
   }
@@ -294,7 +291,7 @@ int pgsql_endCopy(middle_pgsql_t::table_desc *table)
     // Terminate any pending COPY */
     if (table->copyMode) {
         PGconn *sql_conn = table->sql_conn;
-        int stop = PQputCopyEnd(sql_conn, NULL);
+        int stop = PQputCopyEnd(sql_conn, nullptr);
         if (stop != 1) {
             fprintf(stderr, "COPY_END for %s failed: %s\n", table->copy, PQerrorMessage(sql_conn));
             util::exit_nicely();
@@ -313,7 +310,7 @@ int pgsql_endCopy(middle_pgsql_t::table_desc *table)
 }
 } // anonymous namespace
 
-int middle_pgsql_t::local_nodes_set(const osmid_t& id, const double& lat,
+void middle_pgsql_t::local_nodes_set(const osmid_t& id, const double& lat,
                                     const double& lon, const taglist_t &tags)
 {
     if( node_table->copyMode )
@@ -323,48 +320,48 @@ int middle_pgsql_t::local_nodes_set(const osmid_t& id, const double& lat,
       char *buffer = (char *)alloca( length );
 #ifdef FIXED_POINT
       ramNode n(lon, lat);
-      if( snprintf(buffer, length, "%" PRIdOSMID "\t%d\t%d\t%s\n",
-                   id, n.int_lat(), n.int_lon(), tag_buf ) > (length-10) )
-      { fprintf( stderr, "buffer overflow node id %" PRIdOSMID "\n", id); return 1; }
+      if (snprintf(buffer, length, "%" PRIdOSMID "\t%d\t%d\t%s\n",
+                   id, n.int_lat(), n.int_lon(), tag_buf ) > (length-10)) {
+         throw std::runtime_error((boost::format("Buffer overflow node id %1%") % id).str());
+      }
 #else
-      if( snprintf( buffer, length, "%" PRIdOSMID "\t%.10f\t%.10f\t%s\n", id, lat, lon, tag_buf ) > (length-10) )
-      { fprintf( stderr, "buffer overflow node id %" PRIdOSMID "\n", id); return 1; }
+      if (snprintf( buffer, length, "%" PRIdOSMID "\t%.10f\t%.10f\t%s\n", id, lat, lon, tag_buf ) > (length-10)) {
+        throw std::runtime_error((boost::format("Buffer overflow node id %1%") % id).str());
+      }
 #endif
       pgsql_CopyData(__FUNCTION__, node_table->sql_conn, buffer);
-      return 0;
-    }
-
-    // Four params: id, lat, lon, tags */
-    const char *paramValues[4];
-    char *buffer = (char *)alloca(64);
-    char *ptr = buffer;
-    paramValues[0] = ptr;
-    ptr += sprintf( ptr, "%" PRIdOSMID, id ) + 1;
-    paramValues[1] = ptr;
+    } else {
+        // Four params: id, lat, lon, tags */
+        const char *paramValues[4];
+        char *buffer = (char *)alloca(64);
+        char *ptr = buffer;
+        paramValues[0] = ptr;
+        ptr += sprintf( ptr, "%" PRIdOSMID, id ) + 1;
+        paramValues[1] = ptr;
 #ifdef FIXED_POINT
-    ramNode n(lon, lat);
-    ptr += sprintf(ptr, "%d", n.int_lat()) + 1;
-    paramValues[2] = ptr;
-    sprintf(ptr, "%d", n.int_lon());
+        ramNode n(lon, lat);
+        ptr += sprintf(ptr, "%d", n.int_lat()) + 1;
+        paramValues[2] = ptr;
+        sprintf(ptr, "%d", n.int_lon());
 #else
-    ptr += sprintf( ptr, "%.10f", lat ) + 1;
-    paramValues[2] = ptr;
-    sprintf( ptr, "%.10f", lon );
+        ptr += sprintf( ptr, "%.10f", lat ) + 1;
+        paramValues[2] = ptr;
+        sprintf( ptr, "%.10f", lon );
 #endif
-    paramValues[3] = pgsql_store_tags(tags,0);
-    pgsql_execPrepared(node_table->sql_conn, "insert_node", 4, (const char * const *)paramValues, PGRES_COMMAND_OK);
-    return 0;
+        paramValues[3] = pgsql_store_tags(tags,0);
+        pgsql_execPrepared(node_table->sql_conn, "insert_node", 4, (const char * const *)paramValues, PGRES_COMMAND_OK);
+    }
 }
 
 // This should be made more efficient by using an IN(ARRAY[]) construct */
-int middle_pgsql_t::local_nodes_get_list(nodelist_t &out, const idlist_t nds) const
+size_t middle_pgsql_t::local_nodes_get_list(nodelist_t &out, const idlist_t nds) const
 {
     assert(out.empty());
 
     char tmp[16];
 
     char *tmp2 = (char *)malloc(sizeof(char) * nds.size() * 16);
-    if (tmp2 == NULL) return 0; //failed to allocate memory, return */
+    if (tmp2 == nullptr) return 0; //failed to allocate memory, return */
 
 
     // create a list of ids in tmp2 to query the database  */
@@ -402,20 +399,20 @@ int middle_pgsql_t::local_nodes_get_list(nodelist_t &out, const idlist_t nds) co
     int countPG = PQntuples(res);
 
     //store the pg results in a hashmap and telling it how many we expect
-    boost::unordered_map<osmid_t, osmNode> pg_nodes(countPG);
+    std::unordered_map<osmid_t, osmNode> pg_nodes(countPG);
 
     for (int i = 0; i < countPG; i++) {
-        osmid_t id = strtoosmid(PQgetvalue(res, i, 0), NULL, 10);
+        osmid_t id = strtoosmid(PQgetvalue(res, i, 0), nullptr, 10);
         osmNode node;
 #ifdef FIXED_POINT
-        ramNode n((int) strtol(PQgetvalue(res, i, 2), NULL, 10),
-                  (int) strtol(PQgetvalue(res, i, 1), NULL, 10));
+        ramNode n((int) strtol(PQgetvalue(res, i, 2), nullptr, 10),
+                  (int) strtol(PQgetvalue(res, i, 1), nullptr, 10));
 
         node.lat = n.lat();
         node.lon = n.lon();
 #else
-        node.lat = strtod(PQgetvalue(res, i, 1), NULL);
-        node.lon = strtod(PQgetvalue(res, i, 2), NULL);
+        node.lat = strtod(PQgetvalue(res, i, 1), nullptr);
+        node.lon = strtod(PQgetvalue(res, i, 2), nullptr);
 #endif
         pg_nodes.emplace(id, node);
     }
@@ -425,10 +422,10 @@ int middle_pgsql_t::local_nodes_get_list(nodelist_t &out, const idlist_t nds) co
 
     // If some of the nodes in the way don't exist, the returning list has holes.
     // Merge the two lists removing any holes.
-    unsigned wrtidx = 0;
-    for (unsigned i = 0; i < nds.size(); ++i) {
+    size_t wrtidx = 0;
+    for (size_t i = 0; i < nds.size(); ++i) {
         if (std::isnan(out[i].lat)) {
-            boost::unordered_map<osmid_t, osmNode>::iterator found = pg_nodes.find(nds[i]);
+            std::unordered_map<osmid_t, osmNode>::iterator found = pg_nodes.find(nds[i]);
             if(found != pg_nodes.end()) {
                 out[wrtidx] = found->second;
                 ++wrtidx;
@@ -445,22 +442,24 @@ int middle_pgsql_t::local_nodes_get_list(nodelist_t &out, const idlist_t nds) co
 }
 
 
-int middle_pgsql_t::nodes_set(osmid_t id, double lat, double lon, const taglist_t &tags) {
+void middle_pgsql_t::nodes_set(osmid_t id, double lat, double lon, const taglist_t &tags) {
     cache->set( id, lat, lon, tags );
 
-    return (out_options->flat_node_cache_enabled)
-             ? persistent_cache->set(id, lat, lon)
-             : local_nodes_set(id, lat, lon, tags);
+    if (out_options->flat_node_cache_enabled) {
+        persistent_cache->set(id, lat, lon);
+    } else {
+        local_nodes_set(id, lat, lon, tags);
+    }
 }
 
-int middle_pgsql_t::nodes_get_list(nodelist_t &out, const idlist_t nds) const
+size_t middle_pgsql_t::nodes_get_list(nodelist_t &out, const idlist_t nds) const
 {
     return (out_options->flat_node_cache_enabled)
              ? persistent_cache->get_list(out, nds)
              : local_nodes_get_list(out, nds);
 }
 
-int middle_pgsql_t::local_nodes_delete(osmid_t osm_id)
+void middle_pgsql_t::local_nodes_delete(osmid_t osm_id)
 {
     char const *paramValues[1];
     char buffer[64];
@@ -470,18 +469,22 @@ int middle_pgsql_t::local_nodes_delete(osmid_t osm_id)
     sprintf( buffer, "%" PRIdOSMID, osm_id );
     paramValues[0] = buffer;
     pgsql_execPrepared(node_table->sql_conn, "delete_node", 1, paramValues, PGRES_COMMAND_OK );
-    return 0;
 }
 
-int middle_pgsql_t::nodes_delete(osmid_t osm_id)
+void middle_pgsql_t::nodes_delete(osmid_t osm_id)
 {
-    return ((out_options->flat_node_cache_enabled) ? persistent_cache->set(osm_id, NAN, NAN) : local_nodes_delete(osm_id));
+    if (out_options->flat_node_cache_enabled) {
+        persistent_cache->set(osm_id, NAN, NAN);
+    } else {
+        local_nodes_delete(osm_id);
+    }
 }
 
-int middle_pgsql_t::node_changed(osmid_t osm_id)
+void middle_pgsql_t::node_changed(osmid_t osm_id)
 {
-    if (!mark_pending)
-        return 0;
+    if (!mark_pending) {
+        return;
+    }
 
     char const *paramValues[1];
     char buffer[64];
@@ -512,39 +515,36 @@ int middle_pgsql_t::node_changed(osmid_t osm_id)
         rels_pending_tracker->mark(marked);
     }
     PQclear(res);
-
-    return 0;
 }
 
-int middle_pgsql_t::ways_set(osmid_t way_id, const idlist_t &nds, const taglist_t &tags)
+void middle_pgsql_t::ways_set(osmid_t way_id, const idlist_t &nds, const taglist_t &tags)
 {
     // Three params: id, nodes, tags */
     const char *paramValues[4];
     char *buffer;
 
-    if( way_table->copyMode )
-    {
+    if (way_table->copyMode) {
       const char *tag_buf = pgsql_store_tags(tags,1);
       char *node_buf = pgsql_store_nodes(nds);
       int length = strlen(tag_buf) + strlen(node_buf) + 64;
       buffer = (char *)alloca(length);
-      if( snprintf( buffer, length, "%" PRIdOSMID "\t%s\t%s\n",
-              way_id, node_buf, tag_buf ) > (length-10) )
-      { fprintf( stderr, "buffer overflow way id %" PRIdOSMID "\n", way_id); return 1; }
+      if (snprintf( buffer, length, "%" PRIdOSMID "\t%s\t%s\n",
+              way_id, node_buf, tag_buf ) > (length-10)) {
+          throw std::runtime_error((boost::format("Buffer overflow way id %1%") % way_id).str());
+      }
       pgsql_CopyData(__FUNCTION__, way_table->sql_conn, buffer);
-      return 0;
+    } else {
+        buffer = (char *)alloca(64);
+        char *ptr = buffer;
+        paramValues[0] = ptr;
+        sprintf(ptr, "%" PRIdOSMID, way_id);
+        paramValues[1] = pgsql_store_nodes(nds);
+        paramValues[2] = pgsql_store_tags(tags,0);
+        pgsql_execPrepared(way_table->sql_conn, "insert_way", 3, (const char * const *)paramValues, PGRES_COMMAND_OK);
     }
-    buffer = (char *)alloca(64);
-    char *ptr = buffer;
-    paramValues[0] = ptr;
-    sprintf(ptr, "%" PRIdOSMID, way_id);
-    paramValues[1] = pgsql_store_nodes(nds);
-    paramValues[2] = pgsql_store_tags(tags,0);
-    pgsql_execPrepared(way_table->sql_conn, "insert_way", 3, (const char * const *)paramValues, PGRES_COMMAND_OK);
-    return 0;
 }
 
-int middle_pgsql_t::ways_get(osmid_t id, taglist_t &tags, nodelist_t &nodes) const
+bool middle_pgsql_t::ways_get(osmid_t id, taglist_t &tags, nodelist_t &nodes) const
 {
     char const *paramValues[1];
     PGconn *sql_conn = way_table->sql_conn;
@@ -560,12 +560,12 @@ int middle_pgsql_t::ways_get(osmid_t id, taglist_t &tags, nodelist_t &nodes) con
 
     if (PQntuples(res) != 1) {
         PQclear(res);
-        return 1;
+        return false;
     }
 
     pgsql_parse_tags( PQgetvalue(res, 0, 1), tags );
 
-    size_t num_nodes = strtoul(PQgetvalue(res, 0, 2), NULL, 10);
+    size_t num_nodes = strtoul(PQgetvalue(res, 0, 2), nullptr, 10);
     idlist_t list;
     pgsql_parse_nodes( PQgetvalue(res, 0, 0), list);
     if (num_nodes != list.size()) {
@@ -576,10 +576,10 @@ int middle_pgsql_t::ways_get(osmid_t id, taglist_t &tags, nodelist_t &nodes) con
     PQclear(res);
 
     nodes_get_list(nodes, list);
-    return 0;
+    return true;
 }
 
-int middle_pgsql_t::ways_get_list(const idlist_t &ids, idlist_t &way_ids,
+size_t middle_pgsql_t::ways_get_list(const idlist_t &ids, idlist_t &way_ids,
                                   multitaglist_t &tags, multinodelist_t &nodes) const {
     if (ids.empty())
         return 0;
@@ -589,7 +589,7 @@ int middle_pgsql_t::ways_get_list(const idlist_t &ids, idlist_t &way_ids,
     char const *paramValues[1];
 
     tmp2 = (char *)malloc(sizeof(char)*ids.size()*16);
-    if (tmp2 == NULL) return 0; //failed to allocate memory, return */
+    if (tmp2 == nullptr) return 0; //failed to allocate memory, return */
 
     // create a list of ids in tmp2 to query the database  */
     sprintf(tmp2, "{");
@@ -610,7 +610,7 @@ int middle_pgsql_t::ways_get_list(const idlist_t &ids, idlist_t &way_ids,
     idlist_t wayidspg;
 
     for (int i = 0; i < countPG; i++) {
-        wayidspg.push_back(strtoosmid(PQgetvalue(res, i, 0), NULL, 10));
+        wayidspg.push_back(strtoosmid(PQgetvalue(res, i, 0), nullptr, 10));
     }
 
 
@@ -623,7 +623,7 @@ int middle_pgsql_t::ways_get_list(const idlist_t &ids, idlist_t &way_ids,
                 tags.push_back(taglist_t());
                 pgsql_parse_tags(PQgetvalue(res, j, 2), tags.back());
 
-                size_t num_nodes = strtoul(PQgetvalue(res, j, 3), NULL, 10);
+                size_t num_nodes = strtoul(PQgetvalue(res, j, 3), nullptr, 10);
                 idlist_t list;
                 pgsql_parse_nodes( PQgetvalue(res, j, 1), list);
                 if (num_nodes != list.size()) {
@@ -649,7 +649,7 @@ int middle_pgsql_t::ways_get_list(const idlist_t &ids, idlist_t &way_ids,
 }
 
 
-int middle_pgsql_t::ways_delete(osmid_t osm_id)
+void middle_pgsql_t::ways_delete(osmid_t osm_id)
 {
     char const *paramValues[1];
     char buffer[64];
@@ -659,7 +659,6 @@ int middle_pgsql_t::ways_delete(osmid_t osm_id)
     sprintf( buffer, "%" PRIdOSMID, osm_id );
     paramValues[0] = buffer;
     pgsql_execPrepared(way_table->sql_conn, "delete_way", 1, paramValues, PGRES_COMMAND_OK );
-    return 0;
 }
 
 void middle_pgsql_t::iterate_ways(middle_t::pending_processor& pf)
@@ -681,7 +680,7 @@ void middle_pgsql_t::iterate_ways(middle_t::pending_processor& pf)
     pf.process_ways();
 }
 
-int middle_pgsql_t::way_changed(osmid_t osm_id)
+void middle_pgsql_t::way_changed(osmid_t osm_id)
 {
     char const *paramValues[1];
     char buffer[64];
@@ -701,11 +700,9 @@ int middle_pgsql_t::way_changed(osmid_t osm_id)
         rels_pending_tracker->mark(marked);
     }
     PQclear(res);
-
-    return 0;
 }
 
-int middle_pgsql_t::relations_set(osmid_t id, const memberlist_t &members, const taglist_t &tags)
+void middle_pgsql_t::relations_set(osmid_t id, const memberlist_t &members, const taglist_t &tags)
 {
     // Params: id, way_off, rel_off, parts, members, tags */
     const char *paramValues[6];
@@ -731,48 +728,50 @@ int middle_pgsql_t::relations_set(osmid_t id, const memberlist_t &members, const
                 util::exit_nicely();
         }
         sprintf( buf, "%c%" PRIdOSMID, type, it->id );
-        member_list.push_back(tag(buf, it->role));
+        member_list.push_back(tag_t(buf, it->role));
     }
 
     all_parts.insert(all_parts.end(), node_parts.begin(), node_parts.end());
     all_parts.insert(all_parts.end(), way_parts.begin(), way_parts.end());
     all_parts.insert(all_parts.end(), rel_parts.begin(), rel_parts.end());
 
-    if( rel_table->copyMode )
+    if (rel_table->copyMode)
     {
       char *tag_buf = strdup(pgsql_store_tags(tags,1));
       const char *member_buf = pgsql_store_tags(member_list,1);
       char *parts_buf = pgsql_store_nodes(all_parts);
       int length = strlen(member_buf) + strlen(tag_buf) + strlen(parts_buf) + 64;
       buffer = (char *)alloca(length);
-      if( snprintf( buffer, length, "%" PRIdOSMID "\t%zu\t%zu\t%s\t%s\t%s\n",
+      if (snprintf( buffer, length, "%" PRIdOSMID "\t%zu\t%zu\t%s\t%s\t%s\n",
                     id, node_parts.size(), node_parts.size() + way_parts.size(),
-                    parts_buf, member_buf, tag_buf ) > (length-10) )
-      { fprintf( stderr, "buffer overflow relation id %" PRIdOSMID "\n", id); return 1; }
+                    parts_buf, member_buf, tag_buf ) > (length-10)) {
+          throw std::runtime_error((boost::format("Buffer overflow relation id %1%") % id).str());
+      }
       free(tag_buf);
       pgsql_CopyData(__FUNCTION__, rel_table->sql_conn, buffer);
-      return 0;
+    } else {
+        buffer = (char *)alloca(64);
+        char *ptr = buffer;
+        paramValues[0] = ptr;
+        ptr += sprintf(ptr, "%" PRIdOSMID, id ) + 1;
+        paramValues[1] = ptr;
+        ptr += sprintf(ptr, "%zu", node_parts.size() ) + 1;
+        paramValues[2] = ptr;
+        sprintf( ptr, "%zu", node_parts.size() + way_parts.size() );
+        paramValues[3] = pgsql_store_nodes(all_parts);
+        paramValues[4] = pgsql_store_tags(member_list,0);
+        if (paramValues[4]) {
+            paramValues[4] = strdup(paramValues[4]);
+        }
+        paramValues[5] = pgsql_store_tags(tags,0);
+        pgsql_execPrepared(rel_table->sql_conn, "insert_rel", 6, (const char * const *)paramValues, PGRES_COMMAND_OK);
+        if (paramValues[4]) {
+            free((void *)paramValues[4]);
+        }
     }
-    buffer = (char *)alloca(64);
-    char *ptr = buffer;
-    paramValues[0] = ptr;
-    ptr += sprintf(ptr, "%" PRIdOSMID, id ) + 1;
-    paramValues[1] = ptr;
-    ptr += sprintf(ptr, "%zu", node_parts.size() ) + 1;
-    paramValues[2] = ptr;
-    sprintf( ptr, "%zu", node_parts.size() + way_parts.size() );
-    paramValues[3] = pgsql_store_nodes(all_parts);
-    paramValues[4] = pgsql_store_tags(member_list,0);
-    if( paramValues[4] )
-        paramValues[4] = strdup(paramValues[4]);
-    paramValues[5] = pgsql_store_tags(tags,0);
-    pgsql_execPrepared(rel_table->sql_conn, "insert_rel", 6, (const char * const *)paramValues, PGRES_COMMAND_OK);
-    if( paramValues[4] )
-        free((void *)paramValues[4]);
-    return 0;
 }
 
-int middle_pgsql_t::relations_get(osmid_t id, memberlist_t &members, taglist_t &tags) const
+bool middle_pgsql_t::relations_get(osmid_t id, memberlist_t &members, taglist_t &tags) const
 {
     char tmp[16];
     char const *paramValues[1];
@@ -790,13 +789,13 @@ int middle_pgsql_t::relations_get(osmid_t id, memberlist_t &members, taglist_t &
 
     if (PQntuples(res) != 1) {
         PQclear(res);
-        return 1;
+        return false;
     }
 
     pgsql_parse_tags(PQgetvalue(res, 0, 1), tags);
     pgsql_parse_tags(PQgetvalue(res, 0, 0), member_temp);
 
-    if (member_temp.size() != strtoul(PQgetvalue(res, 0, 2), NULL, 10)) {
+    if (member_temp.size() != strtoul(PQgetvalue(res, 0, 2), nullptr, 10)) {
         fprintf(stderr, "Unexpected member_count reading relation %" PRIdOSMID "\n", id);
         util::exit_nicely();
     }
@@ -807,13 +806,13 @@ int middle_pgsql_t::relations_get(osmid_t id, memberlist_t &members, taglist_t &
         char tag = it->key[0];
         OsmType type = (tag == 'n')?OSMTYPE_NODE:(tag == 'w')?OSMTYPE_WAY:(tag == 'r')?OSMTYPE_RELATION:((OsmType)-1);
         members.push_back(member(type,
-                                 strtoosmid(it->key.c_str()+1, NULL, 10 ),
+                                 strtoosmid(it->key.c_str()+1, nullptr, 10 ),
                                  it->value));
     }
-    return 0;
+    return true;
 }
 
-int middle_pgsql_t::relations_delete(osmid_t osm_id)
+void middle_pgsql_t::relations_delete(osmid_t osm_id)
 {
     char const *paramValues[1];
     char buffer[64];
@@ -835,7 +834,6 @@ int middle_pgsql_t::relations_delete(osmid_t osm_id)
         ways_pending_tracker->mark(marked);
     }
     PQclear(res);
-    return 0;
 }
 
 void middle_pgsql_t::iterate_relations(pending_processor& pf)
@@ -856,7 +854,7 @@ void middle_pgsql_t::iterate_relations(pending_processor& pf)
     pf.process_relations();
 }
 
-int middle_pgsql_t::relation_changed(osmid_t osm_id)
+void middle_pgsql_t::relation_changed(osmid_t osm_id)
 {
     char const *paramValues[1];
     char buffer[64];
@@ -877,7 +875,6 @@ int middle_pgsql_t::relation_changed(osmid_t osm_id)
         rels_pending_tracker->mark(marked);
     }
     PQclear(res);
-    return 0;
 }
 
 idlist_t middle_pgsql_t::relations_using_way(osmid_t way_id) const
@@ -895,7 +892,7 @@ idlist_t middle_pgsql_t::relations_using_way(osmid_t way_id) const
     const int ntuples = PQntuples(result);
     idlist_t rel_ids(ntuples);
     for (int i = 0; i < ntuples; ++i) {
-        rel_ids[i] = strtoosmid(PQgetvalue(result, i, 0), NULL, 10);
+        rel_ids[i] = strtoosmid(PQgetvalue(result, i, 0), nullptr, 10);
     }
     PQclear(result);
 
@@ -904,24 +901,24 @@ idlist_t middle_pgsql_t::relations_using_way(osmid_t way_id) const
 
 void middle_pgsql_t::analyze(void)
 {
-    for (int i=0; i<num_tables; i++) {
-        PGconn *sql_conn = tables[i].sql_conn;
+    for (auto& table: tables) {
+        PGconn *sql_conn = table.sql_conn;
 
-        if (tables[i].analyze) {
-            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", tables[i].analyze);
+        if (table.analyze) {
+            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", table.analyze);
         }
     }
 }
 
 void middle_pgsql_t::end(void)
 {
-    for (int i=0; i<num_tables; i++) {
-        PGconn *sql_conn = tables[i].sql_conn;
+    for (auto& table: tables) {
+        PGconn *sql_conn = table.sql_conn;
 
         // Commit transaction */
-        if (tables[i].stop && tables[i].transactionMode) {
-            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", tables[i].stop);
-            tables[i].transactionMode = 0;
+        if (table.stop && table.transactionMode) {
+            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", table.stop);
+            table.transactionMode = 0;
         }
 
     }
@@ -954,10 +951,12 @@ static void set_prefix_and_tbls(const struct options_t *options, const char **st
     char buffer[1024];
     const char *source;
     char *dest;
-    char *openbrace = NULL;
+    char *openbrace = nullptr;
     int copied = 0;
 
-    if (*string == NULL) return;
+    if (*string == nullptr) {
+        return;
+    }
     source = *string;
     dest = buffer;
 
@@ -1012,7 +1011,7 @@ static void set_prefix_and_tbls(const struct options_t *options, const char **st
     *string = strdup(buffer);
 }
 
-int middle_pgsql_t::connect(table_desc& table) {
+void middle_pgsql_t::connect(table_desc& table) {
     PGconn *sql_conn;
 
     set_prefix_and_tbls(out_options, &(table.name));
@@ -1027,24 +1026,20 @@ int middle_pgsql_t::connect(table_desc& table) {
     set_prefix_and_tbls(out_options, &(table.array_indexes));
 
     fprintf(stderr, "Setting up table: %s\n", table.name);
-    sql_conn = PQconnectdb(out_options->conninfo.c_str());
+    sql_conn = PQconnectdb(out_options->database_options.conninfo().c_str());
 
-    // Check to see that the backend connection was successfully made */
+    // Check to see that the backend connection was successfully made, and if not, exit */
     if (PQstatus(sql_conn) != CONNECTION_OK) {
         fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(sql_conn));
-        return 1;
+        util::exit_nicely();
     }
     table.sql_conn = sql_conn;
-    return 0;
 }
 
-int middle_pgsql_t::start(const options_t *out_options_)
+void middle_pgsql_t::start(const options_t *out_options_)
 {
     out_options = out_options_;
-    PGresult   *res;
-    int i;
-    int dropcreate = !out_options->append;
-    char * sql;
+    bool dropcreate = !out_options->append; ///< If tables need to be dropped and created anew
 
     ways_pending_tracker.reset(new id_tracker());
     rels_pending_tracker.reset(new id_tracker());
@@ -1056,14 +1051,14 @@ int middle_pgsql_t::start(const options_t *out_options_)
     // and pass that via the constructor to middle_t, so that middle_t
     // itself doesn't need to know about details of the output.
     if (out_options->output_backend == "gazetteer") {
-        way_table->array_indexes = NULL;
+        way_table->array_indexes = nullptr;
         mark_pending = false;
     }
 
     append = out_options->append;
     // reset this on every start to avoid options from last run
     // staying set for the second.
-    build_indexes = 0;
+    build_indexes = !append && !out_options->droptemp;
 
     cache.reset(new node_ram_cache( out_options->alloc_chunkwise | ALLOC_LOSSY, out_options->cache, out_options->scale));
     if (out_options->flat_node_cache_enabled) persistent_cache.reset(new node_persistent_cache(out_options, out_options->append, false, cache));
@@ -1071,11 +1066,9 @@ int middle_pgsql_t::start(const options_t *out_options_)
     fprintf(stderr, "Mid: pgsql, scale=%d cache=%d\n", out_options->scale, out_options->cache);
 
     // We use a connection per table to enable the use of COPY */
-    for (i=0; i<num_tables; i++) {
-        //bomb if you cant connect
-        if(connect(tables[i]))
-            util::exit_nicely();
-        PGconn* sql_conn = tables[i].sql_conn;
+    for (auto& table: tables) {
+        connect(table);
+        PGconn* sql_conn = table.sql_conn;
 
         /*
          * To allow for parallelisation, the second phase (iterate_ways), cannot be run
@@ -1093,102 +1086,46 @@ int middle_pgsql_t::start(const options_t *out_options_)
          */
         pgsql_exec(sql_conn, PGRES_COMMAND_OK, "SET synchronous_commit TO off;");
 
-        /* Not really the right place for this test, but we need a live
-         * connection that not used for anything else yet, and we'd like to
-         * warn users *before* we start doing mountains of work */
-        if (i == t_node)
-        {
-            res = PQexec(sql_conn, "select 1 from pg_opclass where opcname='gist__intbig_ops'" );
-            if(PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
-            {
-                /* intarray is problematic now; causes at least postgres 8.4
-                 * to not use the index on nodes[]/parts[] which slows diff
-                 * updates to a crawl!
-                 * If someone find a way to fix this rather than bow out here,
-                 * please do.*/
-
-                fprintf(stderr,
-                    "\n"
-                    "The target database has the intarray contrib module loaded.\n"
-                    "While required for earlier versions of osm2pgsql, intarray \n"
-                    "is now unnecessary and will interfere with osm2pgsql's array\n"
-                    "handling. Please use a database without intarray.\n\n");
-                util::exit_nicely();
-            }
-            PQclear(res);
-
-            if (out_options->append)
-            {
-                sql = (char *)malloc (2048);
-                snprintf(sql, 2047, "SELECT id FROM %s LIMIT 1", tables[t_node].name);
-                res = PQexec(sql_conn, sql );
-                free(sql);
-                sql = NULL;
-                if(PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
-                {
-                    int size = PQfsize(res, 0);
-                    if (size != sizeof(osmid_t))
-                    {
-                        fprintf(stderr,
-                            "\n"
-                            "The target database has been created with %dbit ID fields,\n"
-                            "but this version of osm2pgsql has been compiled to use %ldbit IDs.\n"
-                            "You cannot append data to this database with this program.\n"
-                            "Either re-create the database or use a matching osm2pgsql.\n\n",
-                            size * 8, sizeof(osmid_t) * 8);
-                        util::exit_nicely();
-                    }
-                }
-                PQclear(res);
-            }
-
-            if(!out_options->append)
-                build_indexes = 1;
-        }
-
         pgsql_exec(sql_conn, PGRES_COMMAND_OK, "SET client_min_messages = WARNING");
         if (dropcreate) {
-            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "DROP TABLE IF EXISTS %s", tables[i].name);
+            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "DROP TABLE IF EXISTS %s", table.name);
         }
 
-        if (tables[i].start) {
-            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", tables[i].start);
-            tables[i].transactionMode = 1;
+        if (table.start) {
+            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", table.start);
+            table.transactionMode = 1;
         }
 
-        if (dropcreate && tables[i].create) {
-            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", tables[i].create);
-            if (tables[i].create_index) {
-              pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", tables[i].create_index);
+        if (dropcreate && table.create) {
+            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", table.create);
+            if (table.create_index) {
+              pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", table.create_index);
             }
         }
         pgsql_exec(sql_conn, PGRES_COMMAND_OK, "RESET client_min_messages");
 
-        if (tables[i].prepare) {
-            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", tables[i].prepare);
+        if (table.prepare) {
+            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", table.prepare);
         }
 
-        if (append && tables[i].prepare_intarray) {
-            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", tables[i].prepare_intarray);
+        if (append && table.prepare_intarray) {
+            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", table.prepare_intarray);
         }
 
-        if (tables[i].copy) {
-            pgsql_exec(sql_conn, PGRES_COPY_IN, "%s", tables[i].copy);
-            tables[i].copyMode = 1;
+        if (table.copy) {
+            pgsql_exec(sql_conn, PGRES_COPY_IN, "%s", table.copy);
+            table.copyMode = 1;
         }
     }
-
-    return 0;
 }
 
 void middle_pgsql_t::commit(void) {
-    int i;
-    for (i=0; i<num_tables; i++) {
-        PGconn *sql_conn = tables[i].sql_conn;
-        pgsql_endCopy(&tables[i]);
-        if (tables[i].stop && tables[i].transactionMode) {
-            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", tables[i].stop);
-            tables[i].transactionMode = 0;
+    for (auto& table: tables) {
+        PGconn *sql_conn = table.sql_conn;
+        pgsql_endCopy(&table);
+        if (table.stop && table.transactionMode) {
+            pgsql_exec(sql_conn, PGRES_COMMAND_OK, "%s", table.stop);
+            table.transactionMode = 0;
         }
     }
     // Make sure the flat nodes are committed to disk or there will be
@@ -1196,11 +1133,10 @@ void middle_pgsql_t::commit(void) {
     if (out_options->flat_node_cache_enabled) persistent_cache.reset();
 }
 
-void *middle_pgsql_t::pgsql_stop_one(void *arg)
+void middle_pgsql_t::pgsql_stop_one(table_desc *table)
 {
     time_t start, end;
 
-    struct table_desc *table = (struct table_desc *)arg;
     PGconn *sql_conn = table->sql_conn;
 
     fprintf(stderr, "Stopping table: %s\n", table->name);
@@ -1217,67 +1153,32 @@ void *middle_pgsql_t::pgsql_stop_one(void *arg)
     }
 
     PQfinish(sql_conn);
-    table->sql_conn = NULL;
+    table->sql_conn = nullptr;
     time(&end);
     fprintf(stderr, "Stopped table: %s in %is\n", table->name, (int)(end - start));
-    return NULL;
 }
 
-namespace {
-/* Using pthreads requires us to shoe-horn everything into various void*
- * pointers. Improvement for the future: just use boost::thread. */
-struct pthread_thunk {
-    middle_pgsql_t *obj;
-    void *ptr;
-};
-
-extern "C" void *pthread_middle_pgsql_stop_one(void *arg) {
-    pthread_thunk *thunk = static_cast<pthread_thunk *>(arg);
-    return thunk->obj->pgsql_stop_one(thunk->ptr);
-}
-} // anonymous namespace
 
 void middle_pgsql_t::stop(void)
 {
-    int i;
-#ifdef HAVE_PTHREAD
-    pthread_t threads[num_tables];
-#endif
-
     cache.reset();
     if (out_options->flat_node_cache_enabled) persistent_cache.reset();
 
-#ifdef HAVE_PTHREAD
-    pthread_thunk thunks[num_tables];
-    for (i=0; i<num_tables; i++) {
-        thunks[i].obj = this;
-        thunks[i].ptr = &tables[i];
-    }
+    std::vector<std::future<void>> futures;
+    futures.reserve(num_tables);
 
-    for (i=0; i<num_tables; i++) {
-        int ret = pthread_create(&threads[i], NULL, pthread_middle_pgsql_stop_one, &thunks[i]);
-        if (ret) {
-            fprintf(stderr, "pthread_create() returned an error (%d)", ret);
-            util::exit_nicely();
-        }
+    for (int i = 0; i < num_tables; ++i) {
+        futures.push_back(std::async(&middle_pgsql_t::pgsql_stop_one, this, &tables[i]));
     }
 
-    for (i=0; i<num_tables; i++) {
-        int ret = pthread_join(threads[i], NULL);
-        if (ret) {
-            fprintf(stderr, "pthread_join() returned an error (%d)", ret);
-            util::exit_nicely();
-        }
+    for (auto &f : futures) {
+        f.get();
     }
-#else
-    for (i=0; i<num_tables; i++)
-        pgsql_stop_one(&tables[i]);
-#endif
 }
 
 middle_pgsql_t::middle_pgsql_t()
-    : tables(), num_tables(0), node_table(NULL), way_table(NULL), rel_table(NULL),
-      append(0), mark_pending(true), cache(), persistent_cache(), build_indexes(0)
+    : tables(), num_tables(0), node_table(nullptr), way_table(nullptr), rel_table(nullptr),
+      append(false), mark_pending(true), cache(), persistent_cache(), build_indexes(true)
 {
     /*table = t_node,*/
     tables.push_back(table_desc(
@@ -1285,17 +1186,17 @@ middle_pgsql_t::middle_pgsql_t()
            /*start*/ "BEGIN;\n",
 #ifdef FIXED_POINT
           /*create*/ "CREATE %m TABLE %p_nodes (id " POSTGRES_OSMID_TYPE " PRIMARY KEY {USING INDEX TABLESPACE %i}, lat int4 not null, lon int4 not null, tags text[]) {TABLESPACE %t};\n",
-    /*create_index*/ NULL,
+    /*create_index*/ nullptr,
          /*prepare*/ "PREPARE insert_node (" POSTGRES_OSMID_TYPE ", int4, int4, text[]) AS INSERT INTO %p_nodes VALUES ($1,$2,$3,$4);\n"
 #else
           /*create*/ "CREATE %m TABLE %p_nodes (id " POSTGRES_OSMID_TYPE " PRIMARY KEY {USING INDEX TABLESPACE %i}, lat double precision not null, lon double precision not null, tags text[]) {TABLESPACE %t};\n",
-    /*create_index*/ NULL,
+    /*create_index*/ nullptr,
          /*prepare*/ "PREPARE insert_node (" POSTGRES_OSMID_TYPE ", double precision, double precision, text[]) AS INSERT INTO %p_nodes VALUES ($1,$2,$3,$4);\n"
 #endif
                "PREPARE get_node (" POSTGRES_OSMID_TYPE ") AS SELECT lat,lon,tags FROM %p_nodes WHERE id = $1 LIMIT 1;\n"
                "PREPARE get_node_list(" POSTGRES_OSMID_TYPE "[]) AS SELECT id, lat, lon FROM %p_nodes WHERE id = ANY($1::" POSTGRES_OSMID_TYPE "[]);\n"
                "PREPARE delete_node (" POSTGRES_OSMID_TYPE ") AS DELETE FROM %p_nodes WHERE id = $1;\n",
-/*prepare_intarray*/ NULL,
+/*prepare_intarray*/ nullptr,
             /*copy*/ "COPY %p_nodes FROM STDIN;\n",
          /*analyze*/ "ANALYZE %p_nodes;\n",
             /*stop*/ "COMMIT;\n"
@@ -1305,7 +1206,7 @@ middle_pgsql_t::middle_pgsql_t()
             /*name*/ "%p_ways",
            /*start*/ "BEGIN;\n",
           /*create*/ "CREATE %m TABLE %p_ways (id " POSTGRES_OSMID_TYPE " PRIMARY KEY {USING INDEX TABLESPACE %i}, nodes " POSTGRES_OSMID_TYPE "[] not null, tags text[]) {TABLESPACE %t};\n",
-    /*create_index*/ NULL,
+    /*create_index*/ nullptr,
          /*prepare*/ "PREPARE insert_way (" POSTGRES_OSMID_TYPE ", " POSTGRES_OSMID_TYPE "[], text[]) AS INSERT INTO %p_ways VALUES ($1,$2,$3);\n"
                "PREPARE get_way (" POSTGRES_OSMID_TYPE ") AS SELECT nodes, tags, array_upper(nodes,1) FROM %p_ways WHERE id = $1;\n"
                "PREPARE get_way_list (" POSTGRES_OSMID_TYPE "[]) AS SELECT id, nodes, tags, array_upper(nodes,1) FROM %p_ways WHERE id = ANY($1::" POSTGRES_OSMID_TYPE "[]);\n"
@@ -1324,7 +1225,7 @@ middle_pgsql_t::middle_pgsql_t()
             /*name*/ "%p_rels",
            /*start*/ "BEGIN;\n",
           /*create*/ "CREATE %m TABLE %p_rels(id " POSTGRES_OSMID_TYPE " PRIMARY KEY {USING INDEX TABLESPACE %i}, way_off int2, rel_off int2, parts " POSTGRES_OSMID_TYPE "[], members text[], tags text[]) {TABLESPACE %t};\n",
-    /*create_index*/ NULL,
+    /*create_index*/ nullptr,
          /*prepare*/ "PREPARE insert_rel (" POSTGRES_OSMID_TYPE ", int2, int2, " POSTGRES_OSMID_TYPE "[], text[], text[]) AS INSERT INTO %p_rels VALUES ($1,$2,$3,$4,$5,$6);\n"
                "PREPARE get_rel (" POSTGRES_OSMID_TYPE ") AS SELECT members, tags, array_upper(members,1)/2 FROM %p_rels WHERE id = $1;\n"
                "PREPARE delete_rel(" POSTGRES_OSMID_TYPE ") AS DELETE FROM %p_rels WHERE id = $1;\n",
@@ -1350,15 +1251,15 @@ middle_pgsql_t::middle_pgsql_t()
 }
 
 middle_pgsql_t::~middle_pgsql_t() {
-    for (int i=0; i < num_tables; i++) {
-        if (tables[i].sql_conn) {
-            PQfinish(tables[i].sql_conn);
+    for (auto& table: tables) {
+        if (table.sql_conn) {
+            PQfinish(table.sql_conn);
         }
     }
 
 }
 
-boost::shared_ptr<const middle_query_t> middle_pgsql_t::get_instance() const {
+std::shared_ptr<const middle_query_t> middle_pgsql_t::get_instance() const {
     middle_pgsql_t* mid = new middle_pgsql_t();
     mid->out_options = out_options;
     mid->append = out_options->append;
@@ -1374,9 +1275,7 @@ boost::shared_ptr<const middle_query_t> middle_pgsql_t::get_instance() const {
 
     // We use a connection per table to enable the use of COPY */
     for(int i=0; i<num_tables; i++) {
-        //bomb if you cant connect
-        if(mid->connect(mid->tables[i]))
-            util::exit_nicely();
+        mid->connect(mid->tables[i]);
         PGconn* sql_conn = mid->tables[i].sql_conn;
 
         if (tables[i].prepare) {
@@ -1388,7 +1287,7 @@ boost::shared_ptr<const middle_query_t> middle_pgsql_t::get_instance() const {
         }
     }
 
-    return boost::shared_ptr<const middle_query_t>(mid);
+    return std::shared_ptr<const middle_query_t>(mid);
 }
 
 size_t middle_pgsql_t::pending_count() const {
diff --git a/middle-pgsql.hpp b/middle-pgsql.hpp
index f418832..71c6280 100644
--- a/middle-pgsql.hpp
+++ b/middle-pgsql.hpp
@@ -15,35 +15,34 @@
 #include "id-tracker.hpp"
 #include <memory>
 #include <vector>
-#include <boost/shared_ptr.hpp>
 
 struct middle_pgsql_t : public slim_middle_t {
     middle_pgsql_t();
     virtual ~middle_pgsql_t();
 
-    int start(const options_t *out_options_);
+    void start(const options_t *out_options_);
     void stop(void);
     void analyze(void);
     void end(void);
     void commit(void);
 
-    int nodes_set(osmid_t id, double lat, double lon, const taglist_t &tags);
-    int nodes_get_list(nodelist_t &out, const idlist_t nds) const;
-    int nodes_delete(osmid_t id);
-    int node_changed(osmid_t id);
+    void nodes_set(osmid_t id, double lat, double lon, const taglist_t &tags);
+    size_t nodes_get_list(nodelist_t &out, const idlist_t nds) const;
+    void nodes_delete(osmid_t id);
+    void node_changed(osmid_t id);
 
-    int ways_set(osmid_t id, const idlist_t &nds, const taglist_t &tags);
-    int ways_get(osmid_t id, taglist_t &tags, nodelist_t &nodes) const;
-    int ways_get_list(const idlist_t &ids, idlist_t &way_ids,
+    void ways_set(osmid_t id, const idlist_t &nds, const taglist_t &tags);
+    bool ways_get(osmid_t id, taglist_t &tags, nodelist_t &nodes) const;
+    size_t ways_get_list(const idlist_t &ids, idlist_t &way_ids,
                       multitaglist_t &tags, multinodelist_t &nodes) const;
 
-    int ways_delete(osmid_t id);
-    int way_changed(osmid_t id);
+    void ways_delete(osmid_t id);
+    void way_changed(osmid_t id);
 
-    int relations_get(osmid_t id, memberlist_t &members, taglist_t &tags) const;
-    int relations_set(osmid_t id, const memberlist_t &members, const taglist_t &tags);
-    int relations_delete(osmid_t id);
-    int relation_changed(osmid_t id);
+    bool relations_get(osmid_t id, memberlist_t &members, taglist_t &tags) const;
+    void relations_set(osmid_t id, const memberlist_t &members, const taglist_t &tags);
+    void relations_delete(osmid_t id);
+    void relation_changed(osmid_t id);
 
     void iterate_ways(middle_t::pending_processor& pf);
     void iterate_relations(pending_processor& pf);
@@ -52,8 +51,6 @@ struct middle_pgsql_t : public slim_middle_t {
 
     std::vector<osmid_t> relations_using_way(osmid_t way_id) const;
 
-    void *pgsql_stop_one(void *arg);
-
     struct table_desc {
         table_desc(const char *name_ = NULL,
                    const char *start_ = NULL,
@@ -82,27 +79,31 @@ struct middle_pgsql_t : public slim_middle_t {
         struct pg_conn *sql_conn;
     };
 
-    virtual boost::shared_ptr<const middle_query_t> get_instance() const;
+    virtual std::shared_ptr<const middle_query_t> get_instance() const;
 private:
+    void pgsql_stop_one(table_desc *table);
 
-    int connect(table_desc& table);
-    int local_nodes_set(const osmid_t& id, const double& lat, const double& lon, const taglist_t &tags);
-    int local_nodes_get_list(nodelist_t &out, const idlist_t nds) const;
-    int local_nodes_delete(osmid_t osm_id);
+    /**
+     * Sets up sql_conn for the table
+     */
+    void connect(table_desc& table);
+    void local_nodes_set(const osmid_t& id, const double& lat, const double& lon, const taglist_t &tags);
+    size_t local_nodes_get_list(nodelist_t &out, const idlist_t nds) const;
+    void local_nodes_delete(osmid_t osm_id);
 
     std::vector<table_desc> tables;
     int num_tables;
     table_desc *node_table, *way_table, *rel_table;
 
-    int append;
+    bool append;
     bool mark_pending;
 
-    boost::shared_ptr<node_ram_cache> cache;
-    boost::shared_ptr<node_persistent_cache> persistent_cache;
+    std::shared_ptr<node_ram_cache> cache;
+    std::shared_ptr<node_persistent_cache> persistent_cache;
 
-    boost::shared_ptr<id_tracker> ways_pending_tracker, rels_pending_tracker;
+    std::shared_ptr<id_tracker> ways_pending_tracker, rels_pending_tracker;
 
-    int build_indexes;
+    bool build_indexes;
 };
 
 #endif
diff --git a/middle-ram.cpp b/middle-ram.cpp
index 4e79d03..9c449d9 100644
--- a/middle-ram.cpp
+++ b/middle-ram.cpp
@@ -8,14 +8,14 @@
 */
 
 #include <stdexcept>
-#include <cstdio>
-#include <cstring>
+
 #include <cassert>
+#include <cstdio>
 
+#include "id-tracker.hpp"
 #include "middle-ram.hpp"
 #include "node-ram-cache.hpp"
 #include "options.hpp"
-#include "id-tracker.hpp"
 
 /* Object storage now uses 2 levels of storage arrays.
  *
@@ -31,55 +31,22 @@
  *
  */
 
-#define BLOCK_SHIFT 10
-#define PER_BLOCK  (1 << BLOCK_SHIFT)
-#define NUM_BLOCKS (1 << (32 - BLOCK_SHIFT))
 
-static osmid_t id2block(osmid_t id)
-{
-    /* + NUM_BLOCKS/2 allows for negative IDs */
-    return (id >> BLOCK_SHIFT) + NUM_BLOCKS/2;
+void middle_ram_t::nodes_set(osmid_t id, double lat, double lon, const taglist_t &tags) {
+    cache->set(id, lat, lon, tags);
 }
 
-static  osmid_t id2offset(osmid_t id)
+void middle_ram_t::ways_set(osmid_t id, const idlist_t &nds, const taglist_t &tags)
 {
-    return id & (PER_BLOCK-1);
-}
-
-int middle_ram_t::nodes_set(osmid_t id, double lat, double lon, const taglist_t &tags) {
-    return cache->set(id, lat, lon, tags);
+    ways.set(id, new ramWay(tags, nds));
 }
 
-int middle_ram_t::ways_set(osmid_t id, const idlist_t &nds, const taglist_t &tags)
+void middle_ram_t::relations_set(osmid_t id, const memberlist_t &members, const taglist_t &tags)
 {
-    int block  = id2block(id);
-    int offset = id2offset(id);
-
-    if (ways[block].empty()) {
-        ways[block].assign(PER_BLOCK, ramWay());
-    }
-
-    ways[block][offset].ndids = nds;
-    ways[block][offset].tags = tags;
-
-    return 0;
+    rels.set(id, new ramRel(tags, members));
 }
 
-int middle_ram_t::relations_set(osmid_t id, const memberlist_t &members, const taglist_t &tags)
-{
-    int block  = id2block(id);
-    int offset = id2offset(id);
-    if (rels[block].empty()) {
-        rels[block].assign(PER_BLOCK, ramRel());
-    }
-
-    rels[block][offset].tags = tags;
-    rels[block][offset].members = members;
-
-    return 0;
-}
-
-int middle_ram_t::nodes_get_list(nodelist_t &out, const idlist_t nds) const
+size_t middle_ram_t::nodes_get_list(nodelist_t &out, const idlist_t nds) const
 {
     for (idlist_t::const_iterator it = nds.begin(); it != nds.end(); ++it) {
         osmNode n;
@@ -87,7 +54,7 @@ int middle_ram_t::nodes_get_list(nodelist_t &out, const idlist_t nds) const
             out.push_back(n);
     }
 
-    return out.size();
+    return int(out.size());
 }
 
 void middle_ram_t::iterate_relations(pending_processor& pf)
@@ -127,28 +94,31 @@ void middle_ram_t::release_ways()
     ways.clear();
 }
 
-int middle_ram_t::ways_get(osmid_t id, taglist_t &tags, nodelist_t &nodes) const
+bool middle_ram_t::ways_get(osmid_t id, taglist_t &tags, nodelist_t &nodes) const
 {
-    if (simulate_ways_deleted)
-        return 1;
-
-    int block = id2block(id), offset = id2offset(id);
+    if (simulate_ways_deleted) {
+        return false;
+    }
 
-    if (ways[block].empty() || ways[block][offset].ndids.empty())
-        return 1;
+    auto const *ele = ways.get(id);
 
-    tags = ways[block][offset].tags;
+    if (!ele) {
+        return false;
+    }
 
-    nodes_get_list(nodes, ways[block][offset].ndids);
+    tags = ele->tags;
+    nodes_get_list(nodes, ele->ndids);
 
-    return 0;
+    return true;
 }
 
-int middle_ram_t::ways_get_list(const idlist_t &ids, idlist_t &way_ids,
+size_t middle_ram_t::ways_get_list(const idlist_t &ids, idlist_t &way_ids,
                                 multitaglist_t &tags, multinodelist_t &nodes) const
 {
     if (ids.empty())
+    {
         return 0;
+    }
 
     assert(way_ids.empty());
     tags.assign(ids.size(), taglist_t());
@@ -156,7 +126,7 @@ int middle_ram_t::ways_get_list(const idlist_t &ids, idlist_t &way_ids,
 
     size_t count = 0;
     for (idlist_t::const_iterator it = ids.begin(); it != ids.end(); ++it) {
-        if (ways_get(*it, tags[count], nodes[count]) == 0) {
+        if (ways_get(*it, tags[count], nodes[count])) {
             way_ids.push_back(*it);
             count++;
         } else {
@@ -170,20 +140,21 @@ int middle_ram_t::ways_get_list(const idlist_t &ids, idlist_t &way_ids,
         nodes.resize(count);
     }
 
-    return count;
+    return int(count);
 }
 
-int middle_ram_t::relations_get(osmid_t id, memberlist_t &members, taglist_t &tags) const
+bool middle_ram_t::relations_get(osmid_t id, memberlist_t &members, taglist_t &tags) const
 {
-    int block = id2block(id), offset = id2offset(id);
+    auto const *ele = rels.get(id);
 
-    if (rels[block].empty() || rels[block][offset].members.empty())
-        return 1;
+    if (!ele) {
+        return false;
+    }
 
-    members = rels[block][offset].members;
-    tags = rels[block][offset].tags;
+    tags = ele->tags;
+    members = ele->members;
 
-    return 0;
+    return true;
 }
 
 void middle_ram_t::analyze(void)
@@ -196,7 +167,7 @@ void middle_ram_t::end(void)
     /* No need */
 }
 
-int middle_ram_t::start(const options_t *out_options_)
+void middle_ram_t::start(const options_t *out_options_)
 {
     out_options = out_options_;
     /* latlong has a range of +-180, mercator +-20000
@@ -205,13 +176,11 @@ int middle_ram_t::start(const options_t *out_options_)
     cache.reset(new node_ram_cache(out_options->alloc_chunkwise, out_options->cache, out_options->scale));
 
     fprintf( stderr, "Mid: Ram, scale=%d\n", out_options->scale );
-
-    return 0;
 }
 
 void middle_ram_t::stop(void)
 {
-    cache.reset(NULL);
+    cache.reset(nullptr);
 
     release_ways();
     release_relations();
@@ -221,11 +190,8 @@ void middle_ram_t::commit(void) {
 }
 
 middle_ram_t::middle_ram_t():
-    ways(), rels(), cache(),
-    simulate_ways_deleted(false)
+    ways(), rels(), cache(), simulate_ways_deleted(false)
 {
-    ways.resize(NUM_BLOCKS); memset(&ways[0], 0, NUM_BLOCKS * sizeof ways[0]);
-    rels.resize(NUM_BLOCKS); memset(&rels[0], 0, NUM_BLOCKS * sizeof rels[0]);
 }
 
 middle_ram_t::~middle_ram_t() {
@@ -252,7 +218,7 @@ void no_delete(const middle_ram_t * middle) {
 
 }
 
-boost::shared_ptr<const middle_query_t> middle_ram_t::get_instance() const {
+std::shared_ptr<const middle_query_t> middle_ram_t::get_instance() const {
     //shallow copy here because readonly access is thread safe
-    return boost::shared_ptr<const middle_query_t>(this, no_delete);
+    return std::shared_ptr<const middle_query_t>(this, no_delete);
 }
diff --git a/middle-ram.hpp b/middle-ram.hpp
index 8eec63b..32f3bff 100644
--- a/middle-ram.hpp
+++ b/middle-ram.hpp
@@ -13,35 +13,98 @@
 
 #include "middle.hpp"
 #include <vector>
+#include <array>
 
 struct node_ram_cache;
 struct options_t;
 
+template <typename T, size_t N>
+class cache_block_t
+{
+    std::array<std::unique_ptr<T>, N> arr;
+public:
+    void set(size_t idx, T *ele) { arr[idx].reset(ele); }
+
+    T const *get(size_t idx) const { return arr[idx].get(); }
+};
+
+template <typename T, size_t BLOCK_SHIFT>
+class elem_cache_t
+{
+    constexpr static size_t per_block() { return 1 << BLOCK_SHIFT; }
+    constexpr static size_t num_blocks() { return 1 << (32 - BLOCK_SHIFT); }
+
+    constexpr static size_t id2block(osmid_t id)
+    {
+        /* + NUM_BLOCKS/2 allows for negative IDs */
+        return (id >> BLOCK_SHIFT) + num_blocks()/2;
+    }
+
+    constexpr static size_t id2offset(osmid_t id)
+    {
+        return id & (per_block()-1);
+    }
+
+    typedef cache_block_t<T, 1 << BLOCK_SHIFT> element_t;
+    std::vector<std::unique_ptr<element_t>> arr;
+public:
+    elem_cache_t() : arr(num_blocks()) {}
+
+    void set(osmid_t id, T *ele)
+    {
+        const size_t block = id2block(id);
+
+        if (!arr[block]) {
+            arr[block].reset(new element_t());
+        }
+
+        arr[block]->set(id2offset(id), ele);
+    }
+
+    T const *get(osmid_t id) const
+    {
+        const size_t block = id2block(id);
+
+        if (!arr[block]) {
+            return 0;
+        }
+
+        return arr[block]->get(id2offset(id));
+    }
+
+    void clear()
+    {
+        for (auto &ele : arr) {
+            ele.release();
+        }
+    }
+};
+
 struct middle_ram_t : public middle_t {
     middle_ram_t();
     virtual ~middle_ram_t();
 
-    int start(const options_t *out_options_);
+    void start(const options_t *out_options_);
     void stop(void);
     void analyze(void);
     void end(void);
     void commit(void);
 
-    int nodes_set(osmid_t id, double lat, double lon, const taglist_t &tags);
-    int nodes_get_list(nodelist_t &out, const idlist_t nds) const;
+    void nodes_set(osmid_t id, double lat, double lon, const taglist_t &tags);
+    size_t nodes_get_list(nodelist_t &out, const idlist_t nds) const;
     int nodes_delete(osmid_t id);
     int node_changed(osmid_t id);
 
-    int ways_set(osmid_t id, const idlist_t &nds, const taglist_t &tags);
-    int ways_get(osmid_t id, taglist_t &tags, nodelist_t &nodes) const;
-    int ways_get_list(const idlist_t &ids, idlist_t &way_ids,
+    void ways_set(osmid_t id, const idlist_t &nds, const taglist_t &tags);
+    bool ways_get(osmid_t id, taglist_t &tags, nodelist_t &nodes) const;
+    size_t ways_get_list(const idlist_t &ids, idlist_t &way_ids,
                       multitaglist_t &tags, multinodelist_t &nodes) const;
 
     int ways_delete(osmid_t id);
     int way_changed(osmid_t id);
 
-    int relations_get(osmid_t id, memberlist_t &members, taglist_t &tags) const;
-    int relations_set(osmid_t id, const memberlist_t &members, const taglist_t &tags);
+    bool relations_get(osmid_t id, memberlist_t &members, taglist_t &tags) const;
+    void relations_set(osmid_t id, const memberlist_t &members, const taglist_t &tags);
     int relations_delete(osmid_t id);
     int relation_changed(osmid_t id);
 
@@ -52,7 +115,7 @@ struct middle_ram_t : public middle_t {
 
     size_t pending_count() const;
 
-    virtual boost::shared_ptr<const middle_query_t> get_instance() const;
+    virtual std::shared_ptr<const middle_query_t> get_instance() const;
 private:
 
     void release_ways();
@@ -61,17 +124,21 @@ private:
     struct ramWay {
         taglist_t tags;
         idlist_t ndids;
+
+        ramWay(const taglist_t &t, const idlist_t &n) : tags(t), ndids(n) {}
     };
 
     struct ramRel {
         taglist_t tags;
         memberlist_t members;
+
+        ramRel(const taglist_t &t, const memberlist_t &m) : tags(t), members(m) {}
     };
 
-    std::vector<std::vector<ramWay> > ways;
-    std::vector<std::vector<ramRel> > rels;
+    elem_cache_t<ramWay, 10> ways;
+    elem_cache_t<ramRel, 10> rels;
 
-    std::auto_ptr<node_ram_cache> cache;
+    std::unique_ptr<node_ram_cache> cache;
 
     /* the previous behaviour of iterate_ways was to delete all ways as they
      * were being iterated. this doesn't work now that the output handles its
@@ -81,6 +148,4 @@ private:
     bool simulate_ways_deleted;
 };
 
-extern middle_ram_t mid_ram;
-
 #endif
diff --git a/middle.cpp b/middle.cpp
index dcaae5b..c9ddcd4 100644
--- a/middle.cpp
+++ b/middle.cpp
@@ -2,13 +2,13 @@
 #include "middle-pgsql.hpp"
 #include "middle-ram.hpp"
 
-#include <boost/make_shared.hpp>
+#include <memory>
 
-boost::shared_ptr<middle_t> middle_t::create_middle(const bool slim)
+std::shared_ptr<middle_t> middle_t::create_middle(const bool slim)
 {
      if(slim)
-         return boost::make_shared<middle_pgsql_t>();
+         return std::make_shared<middle_pgsql_t>();
      else
-         return boost::make_shared<middle_ram_t>();
+         return std::make_shared<middle_ram_t>();
 }
 
diff --git a/middle.hpp b/middle.hpp
index 104c653..b85da7b 100644
--- a/middle.hpp
+++ b/middle.hpp
@@ -1,6 +1,6 @@
-/* Common middle layer interface */
-
-/* Each middle layer data store must provide methods for
+/**
+ * Common middle layer interface
+ * Each middle layer data store must provide methods for
  * storing and retrieving node and way data.
  */
 
@@ -10,42 +10,62 @@
 #include "osmtypes.hpp"
 
 #include <cstddef>
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
 struct options_t;
 
+/**
+ * object which stores OSM node/ways/relations from the input file
+ */
 struct middle_query_t {
     virtual ~middle_query_t() {}
 
-    virtual int nodes_get_list(nodelist_t &out, const idlist_t nds) const = 0;
+    virtual size_t nodes_get_list(nodelist_t &out, const idlist_t nds) const = 0;
 
-    virtual int ways_get(osmid_t id, taglist_t &tags, nodelist_t &nodes) const = 0;
+    /**
+     * Retrives a single way from the ways storage.
+     * \return true if the way was retrieved
+     * \param id id of the way to retrive
+     */
+    virtual bool ways_get(osmid_t id, taglist_t &tags, nodelist_t &nodes) const = 0;
 
-    virtual int ways_get_list(const idlist_t &ids, idlist_t &way_ids,
+    virtual size_t ways_get_list(const idlist_t &ids, idlist_t &way_ids,
                               multitaglist_t &tags,
                               multinodelist_t &nodes) const = 0;
 
-    virtual int relations_get(osmid_t id, memberlist_t &members, taglist_t &tags) const = 0;
-
+    /**
+     * Retrives a single relation from the relation storage.
+     * \return true if the relation was retrieved
+     * \param id id of the relation to retrive
+     */
+    virtual bool relations_get(osmid_t id, memberlist_t &members, taglist_t &tags) const = 0;
+
+    /*
+     * Retrieve a list of relations with a particular way as a member
+     * \param way_id ID of the way to check
+     */
     virtual idlist_t relations_using_way(osmid_t way_id) const = 0;
 
-    virtual boost::shared_ptr<const middle_query_t> get_instance() const = 0;
+    virtual std::shared_ptr<const middle_query_t> get_instance() const = 0;
 };
 
+/**
+ * A specialized middle backend which is persistent, and supports updates
+ */
 struct middle_t : public middle_query_t {
-    static boost::shared_ptr<middle_t> create_middle(bool slim);
+    static std::shared_ptr<middle_t> create_middle(bool slim);
 
     virtual ~middle_t() {}
 
-    virtual int start(const options_t *out_options_) = 0;
+    virtual void start(const options_t *out_options_) = 0;
     virtual void stop(void) = 0;
     virtual void analyze(void) = 0;
     virtual void end(void) = 0;
     virtual void commit(void) = 0;
 
-    virtual int nodes_set(osmid_t id, double lat, double lon, const taglist_t &tags) = 0;
-    virtual int ways_set(osmid_t id, const idlist_t &nds, const taglist_t &tags) = 0;
-    virtual int relations_set(osmid_t id, const memberlist_t &members, const taglist_t &tags) = 0;
+    virtual void nodes_set(osmid_t id, double lat, double lon, const taglist_t &tags) = 0;
+    virtual void ways_set(osmid_t id, const idlist_t &nds, const taglist_t &tags) = 0;
+    virtual void relations_set(osmid_t id, const memberlist_t &members, const taglist_t &tags) = 0;
 
     struct pending_processor {
         virtual ~pending_processor() {}
@@ -66,14 +86,14 @@ struct middle_t : public middle_query_t {
 struct slim_middle_t : public middle_t {
     virtual ~slim_middle_t() {}
 
-    virtual int nodes_delete(osmid_t id) = 0;
-    virtual int node_changed(osmid_t id) = 0;
+    virtual void nodes_delete(osmid_t id) = 0;
+    virtual void node_changed(osmid_t id) = 0;
 
-    virtual int ways_delete(osmid_t id) = 0;
-    virtual int way_changed(osmid_t id) = 0;
+    virtual void ways_delete(osmid_t id) = 0;
+    virtual void way_changed(osmid_t id) = 0;
 
-    virtual int relations_delete(osmid_t id) = 0;
-    virtual int relation_changed(osmid_t id) = 0;
+    virtual void relations_delete(osmid_t id) = 0;
+    virtual void relation_changed(osmid_t id) = 0;
 };
 
 #endif
diff --git a/multi.lua b/multi.lua
index 550c0de..f33e1b3 100644
--- a/multi.lua
+++ b/multi.lua
@@ -119,7 +119,7 @@ end
 -- true
 -- > = yesno("foo")
 -- true
--- 
+--
 -- A typical usage would be on a tag like bridge, tunnel, or shelter, but not
 -- a tag like oneway which could be yes, no, reverse, or unset
 function yesno (v)
diff --git a/node-persistent-cache-reader.cpp b/node-persistent-cache-reader.cpp
index c2c8b68..7504ab1 100644
--- a/node-persistent-cache-reader.cpp
+++ b/node-persistent-cache-reader.cpp
@@ -4,14 +4,14 @@
 #include <cstring>
 #include <sys/wait.h>
 #include <sys/time.h>
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
 #include "osmtypes.hpp"
 #include "options.hpp"
 #include "node-persistent-cache.hpp"
 #include "node-ram-cache.hpp"
 
-void test_get_node_list(boost::shared_ptr<node_persistent_cache> cache,
+void test_get_node_list(std::shared_ptr<node_persistent_cache> cache,
                         int itterations, int max_size, int process_number) {
     int i, j, node_cnt, node_cnt_total;
     nodelist_t nodes;
@@ -20,7 +20,7 @@ void test_get_node_list(boost::shared_ptr<node_persistent_cache> cache,
     idlist_t osmids;
 
     node_cnt_total = 0;
-    gettimeofday(&start_overall, NULL);
+    gettimeofday(&start_overall, nullptr);
     for (i = 0; i < itterations; i++) {
         node_cnt = random() % max_size;
         node_cnt_total += node_cnt;
@@ -29,39 +29,39 @@ void test_get_node_list(boost::shared_ptr<node_persistent_cache> cache,
         for (j = 0; j < node_cnt; j++) {
             osmids.push_back(random() % (1 << 31));
         }
-        gettimeofday(&start, NULL);
+        gettimeofday(&start, nullptr);
         cache->get_list(nodes,osmids);
-        gettimeofday(&stop, NULL);
+        gettimeofday(&stop, nullptr);
         double duration = ((stop.tv_sec - start.tv_sec)*1000000.0 + (stop.tv_usec - start.tv_usec))/1000000.0;
         printf("Process %i: Got nodes in %f at a rate of %f/s\n", process_number, duration, node_cnt / duration);
         nodes.clear();
         osmids.clear();
     }
-    gettimeofday(&stop_overall, NULL);
+    gettimeofday(&stop_overall, nullptr);
     double duration = ((stop_overall.tv_sec - start_overall.tv_sec)*1000000.0 + (stop_overall.tv_usec - start_overall.tv_usec))/1000000.0;
     printf("Process %i: Got a total of nodes in %f at a rate of %f/s\n", process_number, duration, node_cnt_total / duration);
 }
 
 int main(int argc, char *argv[]) {
-	int i,p;
-	options_t options;
-	osmNode node;
-	nodelist_t nodes;
-	struct timeval start;
-	idlist_t osmids;
-	int node_cnt;
-	options.append = 1;
-	options.flat_node_cache_enabled = 1;
-	options.flat_node_file = argv[1];
-        boost::shared_ptr<node_ram_cache> ram_cache(new node_ram_cache(0, 10, options.scale));
-        boost::shared_ptr<node_persistent_cache> cache;
+    int i,p;
+    options_t options;
+    osmNode node;
+    nodelist_t nodes;
+    struct timeval start;
+    idlist_t osmids;
+    int node_cnt;
+    options.append = true;
+    options.flat_node_cache_enabled = true;
+    options.flat_node_file = argv[1];
+    auto ram_cache = std::make_shared<node_ram_cache>(0, 10, options.scale);
+    std::shared_ptr<node_persistent_cache> cache;
 
 
 	if (argc > 3) {
 		cache.reset(new node_persistent_cache(&options, 1, true, ram_cache));
 		node_cnt = argc - 2;
 		for (i = 0; i < node_cnt; i++) {
-			osmids.push_back(strtoosmid(argv[2 + i], NULL, 10));
+			osmids.push_back(strtoosmid(argv[2 + i], nullptr, 10));
 		}
 		cache->get_list(nodes, osmids);
 		for (i = 0; i < node_cnt; i++) {
@@ -69,7 +69,7 @@ int main(int argc, char *argv[]) {
 		}
 	} else if (argc == 2) {
             char * state = (char *)malloc(sizeof(char)* 128);
-        gettimeofday(&start, NULL);
+        gettimeofday(&start, nullptr);
         initstate(start.tv_usec, state, 8);
         setstate(state);
 
@@ -91,7 +91,7 @@ int main(int argc, char *argv[]) {
 	            exit(1);
 	        }
 	    }
-	    gettimeofday(&start, NULL);
+	    gettimeofday(&start, nullptr);
 	    initstate(start.tv_usec, state, 8);
 	    setstate(state);
 	    cache.reset(new node_persistent_cache(&options, 1, true, ram_cache));
@@ -102,28 +102,28 @@ int main(int argc, char *argv[]) {
 	        fprintf(stderr,"Exiting process %i\n", p);
 	        exit(0);
 	    } else {
-	        for (p = 0; p < noProcs; p++) wait(NULL);
+	        for (p = 0; p < noProcs; p++) wait(nullptr);
 	    }
         free(state);
 	    fprintf(stderr, "\nAll child processes exited\n");
 #endif
 	} else {
 		cache.reset(new node_persistent_cache(&options, 1, true, ram_cache));
-		if (strstr(argv[2],",") == NULL) {
-			cache->get(&node, strtoosmid(argv[2], NULL, 10));
+		if (strstr(argv[2],",") == nullptr) {
+			cache->get(&node, strtoosmid(argv[2], nullptr, 10));
 			printf("lat: %f / lon: %f\n", node.lat, node.lon);
 		} else {
                     char * node_list = (char *)malloc(sizeof(char) * (strlen(argv[2]) + 1));
 			strcpy(node_list,argv[2]);
 			node_cnt = 1;
 			strtok(node_list,",");
-			while (strtok(NULL,",") != NULL) node_cnt++;
+			while (strtok(nullptr,",") != nullptr) node_cnt++;
 			printf("Processing %i nodes\n", node_cnt);
 			strcpy(node_list,argv[2]);
-			osmids.push_back(strtoosmid(strtok(node_list,","), NULL, 10));
+			osmids.push_back(strtoosmid(strtok(node_list,","), nullptr, 10));
 			for (i = 1; i < node_cnt; i++) {
-				char * tmp = strtok(NULL,",");
-				osmids.push_back(strtoosmid(tmp, NULL, 10));
+				char * tmp = strtok(nullptr,",");
+				osmids.push_back(strtoosmid(tmp, nullptr, 10));
 			}
 			cache->get_list(nodes,osmids);
 			for (i = 0; i < node_cnt; i++) {
diff --git a/node-persistent-cache.cpp b/node-persistent-cache.cpp
index 59c0d97..317459d 100644
--- a/node-persistent-cache.cpp
+++ b/node-persistent-cache.cpp
@@ -2,26 +2,27 @@
 
 #include "config.h"
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
+#include <algorithm>
+#include <stdexcept>
+
+#include <cerrno>
+#include <climits>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+
+#include <fcntl.h>
 #include <string.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/types.h>
 #include <sys/stat.h>
-#include <fcntl.h>
-#include <math.h>
+#include <sys/types.h>
+#include <unistd.h>
 
+#include "node-persistent-cache.hpp"
+#include "options.hpp"
 #include "osmtypes.hpp"
 #include "output.hpp"
-#include "options.hpp"
-#include "node-persistent-cache.hpp"
 #include "util.hpp"
 
-#include <stdexcept>
-#include <algorithm>
-
 #ifdef _WIN32
  #include "win_fsync.h"
  #define lseek64 _lseeki64
@@ -78,7 +79,7 @@ void node_persistent_cache::writeout_dirty_nodes()
 /**
  * Find the cache block with the lowest usage count for replacement
  */
-int node_persistent_cache::replace_block()
+size_t node_persistent_cache::replace_block()
 {
     int min_used = INT_MAX;
     int block_id = -1;
@@ -212,7 +213,7 @@ void node_persistent_cache::nodes_prefetch_async(osmid_t id)
  */
 int node_persistent_cache::load_block(osmid_t block_offset)
 {
-    const int block_id = replace_block();
+    const size_t block_id = replace_block();
 
     if (readNodeBlockCache[block_id].dirty())
     {
@@ -323,7 +324,7 @@ void node_persistent_cache::nodes_set_create_writeout_block()
 #endif
 }
 
-int node_persistent_cache::set_create(osmid_t id, double lat, double lon)
+void node_persistent_cache::set_create(osmid_t id, double lat, double lon)
 {
     assert(!append_mode);
     assert(!read_mode);
@@ -361,11 +362,9 @@ int node_persistent_cache::set_create(osmid_t id, double lat, double lon)
 
     writeNodeBlock.nodes[id & WRITE_NODE_BLOCK_MASK] = ramNode(lon, lat);
     writeNodeBlock.set_dirty();
-
-    return 0;
 }
 
-int node_persistent_cache::set_append(osmid_t id, double lat, double lon)
+void node_persistent_cache::set_append(osmid_t id, double lat, double lon)
 {
     assert(!read_mode);
 
@@ -383,15 +382,15 @@ int node_persistent_cache::set_append(osmid_t id, double lat, double lon)
     }
     readNodeBlockCache[block_id].inc_used();
     readNodeBlockCache[block_id].set_dirty();
-
-    return 1;
 }
 
-int node_persistent_cache::set(osmid_t id, double lat, double lon)
+void node_persistent_cache::set(osmid_t id, double lat, double lon)
 {
-    return append_mode ?
-        set_append(id, lat, lon) :
+    if (append_mode) {
+        set_append(id, lat, lon);
+    } else {
         set_create(id, lat, lon);
+    }
 }
 
 int node_persistent_cache::get(osmNode *out, osmid_t id)
@@ -418,7 +417,7 @@ int node_persistent_cache::get(osmNode *out, osmid_t id)
     return 0;
 }
 
-int node_persistent_cache::get_list(nodelist_t &out, const idlist_t nds)
+size_t node_persistent_cache::get_list(nodelist_t &out, const idlist_t nds)
 {
     set_read_mode();
 
@@ -484,12 +483,11 @@ void node_persistent_cache::set_read_mode()
     read_mode = true;
 }
 
-node_persistent_cache::node_persistent_cache(const options_t *options, int append,
-                                             bool ro, boost::shared_ptr<node_ram_cache> ptr)
-    : node_cache_fd(0), node_cache_fname(NULL), append_mode(0), cacheHeader(),
-      writeNodeBlock(), readNodeBlockCache(NULL), read_mode(ro), ram_cache(ptr)
+node_persistent_cache::node_persistent_cache(const options_t *options, bool append,
+                                             bool ro, std::shared_ptr<node_ram_cache> ptr)
+    : node_cache_fd(0), node_cache_fname(nullptr), append_mode(append), cacheHeader(),
+      writeNodeBlock(), readNodeBlockCache(nullptr), read_mode(ro), ram_cache(ptr)
 {
-    append_mode = append;
     if (options->flat_node_file) {
         node_cache_fname = options->flat_node_file->c_str();
     } else {
@@ -540,11 +538,10 @@ node_persistent_cache::node_persistent_cache(const options_t *options, int appen
 
         if (!read_mode)
         {
-            int err;
             #ifdef HAVE_POSIX_FALLOCATE
+            int err;
             if ((err = posix_fallocate(node_cache_fd, 0,
-                    sizeof(ramNode) * MAXIMUM_INITIAL_ID)) != 0)
-            {
+                    sizeof(ramNode) * MAXIMUM_INITIAL_ID)) != 0) {
                 if (err == ENOSPC) {
                     fprintf(stderr, "Failed to allocate space for node cache file: No space on disk\n");
                 } else if (err == EFBIG) {
@@ -558,6 +555,7 @@ node_persistent_cache::node_persistent_cache(const options_t *options, int appen
             }
             fprintf(stderr, "Allocated space for persistent node cache file\n");
             #endif
+
             writeNodeBlock.nodes = new ramNode[WRITE_NODE_BLOCK_SIZE];
             if (!writeNodeBlock.nodes) {
                 fprintf(stderr, "Out of memory: Failed to allocate node writeout buffer\n");
diff --git a/node-persistent-cache.hpp b/node-persistent-cache.hpp
index 2363d11..9428c82 100644
--- a/node-persistent-cache.hpp
+++ b/node-persistent-cache.hpp
@@ -3,7 +3,7 @@
 
 #include "osmtypes.hpp"
 #include "node-ram-cache.hpp"
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
 #include <vector>
 
@@ -51,21 +51,21 @@ inline bool operator<(osmid_t a, cache_index_entry const &b)
 
 struct node_persistent_cache : public boost::noncopyable
 {
-    node_persistent_cache(const struct options_t *options, int append,
-                          bool ro, boost::shared_ptr<node_ram_cache> ptr);
+    node_persistent_cache(const struct options_t *options, bool append,
+                          bool ro, std::shared_ptr<node_ram_cache> ptr);
     ~node_persistent_cache();
 
-    int set(osmid_t id, double lat, double lon);
+    void set(osmid_t id, double lat, double lon);
     int get(osmNode *out, osmid_t id);
-    int get_list(nodelist_t &out, const idlist_t nds);
+    size_t get_list(nodelist_t &out, const idlist_t nds);
 
 private:
 
-    int set_append(osmid_t id, double lat, double lon);
-    int set_create(osmid_t id, double lat, double lon);
+    void set_append(osmid_t id, double lat, double lon);
+    void set_create(osmid_t id, double lat, double lon);
 
     void writeout_dirty_nodes();
-    int replace_block();
+    size_t replace_block();
     int find_block(osmid_t block_offset);
     void expand_cache(osmid_t block_offset);
     void nodes_prefetch_async(osmid_t id);
@@ -78,7 +78,7 @@ private:
 
     int node_cache_fd;
     const char * node_cache_fname;
-    int append_mode;
+    bool append_mode;
 
     persistentCacheHeader cacheHeader;
     ramNodeBlock writeNodeBlock; /* larger node block for more efficient initial sequential writing of node cache */
@@ -89,7 +89,7 @@ private:
 
     bool read_mode;
 
-    boost::shared_ptr<node_ram_cache> ram_cache;
+    std::shared_ptr<node_ram_cache> ram_cache;
 };
 
 #endif
diff --git a/node-ram-cache.cpp b/node-ram-cache.cpp
index 23f8d24..ef74191 100644
--- a/node-ram-cache.cpp
+++ b/node-ram-cache.cpp
@@ -5,12 +5,16 @@
 
 #include "config.h"
 
+#include <new>
+#include <stdexcept>
+
 #include <cstdio>
 #include <cstdlib>
-#include <cstring>
 
-#include "osmtypes.hpp"
+#include <boost/format.hpp>
+
 #include "node-ram-cache.hpp"
+#include "osmtypes.hpp"
 #include "util.hpp"
 
 /* Here we use a similar storage structure as middle-ram, except we allow
@@ -52,13 +56,15 @@
 
 
 
-#define BLOCK_SHIFT 10
+#define BLOCK_SHIFT 13
 #define PER_BLOCK  (((osmid_t)1) << BLOCK_SHIFT)
 #define NUM_BLOCKS (((osmid_t)1) << (36 - BLOCK_SHIFT))
 
 #define SAFETY_MARGIN 1024*PER_BLOCK*sizeof(ramNode)
 
+#ifdef FIXED_POINT
 int ramNode::scale;
+#endif
 
 static int32_t id2block(osmid_t id)
 {
@@ -107,15 +113,15 @@ ramNode *node_ram_cache::next_chunk() {
 }
 
 
-int node_ram_cache::set_sparse(osmid_t id, const ramNode &coord) {
+void node_ram_cache::set_sparse(osmid_t id, const ramNode &coord) {
     // Sparse cache depends on ordered nodes, reject out-of-order ids.
     // Also check that there is still space.
     if ((maxSparseId && id < maxSparseId)
-        || (sizeSparseTuples > maxSparseTuples)
-        || ( cacheUsed > cacheSize)) {
-        if ((allocStrategy & ALLOC_LOSSY) > 0)
-            return 1;
-        else {
+         || (sizeSparseTuples > maxSparseTuples)
+         || ( cacheUsed > cacheSize)) {
+        if (allocStrategy & ALLOC_LOSSY) {
+            return;
+        } else {
             fprintf(stderr, "\nNode cache size is too small to fit all nodes. Please increase cache size\n");
             util::exit_nicely();
         }
@@ -127,14 +133,15 @@ int node_ram_cache::set_sparse(osmid_t id, const ramNode &coord) {
     sizeSparseTuples++;
     cacheUsed += sizeof(ramNodeID);
     storedNodes++;
-    return 0;
 }
 
-int node_ram_cache::set_dense(osmid_t id, const ramNode &coord) {
+void node_ram_cache::set_dense(osmid_t id, const ramNode &coord) {
     int32_t const block  = id2block(id);
     int const offset = id2offset(id);
 
-    if (maxBlocks == 0) return 1;
+    if (maxBlocks == 0) {
+      return;
+    }
 
     if (!blocks[block].nodes) {
         if (((allocStrategy & ALLOC_SPARSE) > 0) && ( usedBlocks < maxBlocks) && ( cacheUsed > cacheSize)) {
@@ -166,7 +173,7 @@ int node_ram_cache::set_dense(osmid_t id, const ramNode &coord) {
                     /* reuse previous block, as its content is now in the sparse representation */
                     storedNodes -= queue[usedBlocks - 1]->used();
                     blocks[block].nodes = queue[usedBlocks - 1]->nodes;
-                    blocks[queue[usedBlocks - 1]->block_offset].nodes = NULL;
+                    blocks[queue[usedBlocks - 1]->block_offset].nodes = nullptr;
                     usedBlocks--;
                     cacheUsed -= PER_BLOCK * sizeof(ramNode);
                 }
@@ -222,7 +229,7 @@ int node_ram_cache::set_dense(osmid_t id, const ramNode &coord) {
 
             /* Clear old head block and point to new block */
             storedNodes -= queue[0]->used();
-            queue[0]->nodes = NULL;
+            queue[0]->nodes = nullptr;
             queue[0]->reset_used();
             queue[0] = &blocks[block];
         }
@@ -242,14 +249,13 @@ int node_ram_cache::set_dense(osmid_t id, const ramNode &coord) {
                 fprintf( stderr, "WARNING: Found Out of order node %" PRIdOSMID " (%d,%d) - this will impact the cache efficiency\n", id, block, offset );
                 warn_node_order++;
             }
-            return 1;
+            return;
         }
     }
 
     blocks[block].nodes[offset] = coord;
     blocks[block].inc_used();
     storedNodes++;
-    return 0;
 }
 
 
@@ -296,13 +302,14 @@ int node_ram_cache::get_dense(osmNode *out, osmid_t id) {
 
 
 node_ram_cache::node_ram_cache( int strategy, int cacheSizeMB, int fixpointscale )
-    : allocStrategy(ALLOC_DENSE), blocks(NULL), usedBlocks(0),
-      maxBlocks(0), blockCache(NULL), queue(NULL), sparseBlock(NULL),
+    : allocStrategy(ALLOC_DENSE), blocks(nullptr), usedBlocks(0),
+      maxBlocks(0), blockCache(nullptr), queue(nullptr), sparseBlock(nullptr),
       maxSparseTuples(0), sizeSparseTuples(0), maxSparseId(0), cacheUsed(0),
       cacheSize(0), storedNodes(0), totalNodes(0), nodesCacheHits(0),
       nodesCacheLookups(0), warn_node_order(0) {
-
+#ifdef FIXED_POINT
     ramNode::scale = fixpointscale;
+#endif
     blockCache = 0;
     blockCachePos = 0;
     cacheUsed = 0;
@@ -362,15 +369,11 @@ node_ram_cache::node_ram_cache( int strategy, int cacheSizeMB, int fixpointscale
         }
     }
 
-#ifdef __MINGW_H
-    fprintf( stderr, "Node-cache: cache=%ldMB, maxblocks=%d*%d, allocation method=%i\n", (cacheSize >> 20), maxBlocks, PER_BLOCK*sizeof(ramNode), allocStrategy );
-#else
-    fprintf( stderr, "Node-cache: cache=%ldMB, maxblocks=%d*%zd, allocation method=%i\n", (cacheSize >> 20), maxBlocks, PER_BLOCK*sizeof(ramNode), allocStrategy );
-#endif
+    fprintf( stderr, "Node-cache: cache=%" PRId64 "MB, maxblocks=%d*%" PRId64 ", allocation method=%i\n", (cacheSize >> 20), maxBlocks, (int64_t) PER_BLOCK*sizeof(ramNode), allocStrategy );
 }
 
 node_ram_cache::~node_ram_cache() {
-  fprintf( stderr, "node cache: stored: %" PRIdOSMID "(%.2f%%), storage efficiency: %.2f%% (dense blocks: %i, sparse nodes: %li), hit rate: %.2f%%\n",
+  fprintf( stderr, "node cache: stored: %" PRIdOSMID "(%.2f%%), storage efficiency: %.2f%% (dense blocks: %i, sparse nodes: %" PRId64 "), hit rate: %.2f%%\n",
            storedNodes, 100.0f*storedNodes/totalNodes, 100.0f*storedNodes*sizeof(ramNode)/cacheUsed,
            usedBlocks, sizeSparseTuples,
            100.0f*nodesCacheHits/nodesCacheLookups );
@@ -379,7 +382,7 @@ node_ram_cache::~node_ram_cache() {
       if ( (allocStrategy & ALLOC_DENSE_CHUNK) > 0 ) {
           for(int i = 0; i < usedBlocks; ++i) {
               delete[] queue[i]->nodes;
-              queue[i]->nodes = NULL;
+              queue[i]->nodes = nullptr;
           }
       } else {
           free(blockCache);
@@ -393,10 +396,10 @@ node_ram_cache::~node_ram_cache() {
   }
 }
 
-int node_ram_cache::set(osmid_t id, double lat, double lon, const taglist_t &) {
+void node_ram_cache::set(osmid_t id, double lat, double lon, const taglist_t &) {
     if ((id > 0 && id >> BLOCK_SHIFT >> 32) || (id < 0 && ~id >> BLOCK_SHIFT >> 32 )) {
-        fprintf(stderr, "\nAbsolute node IDs must not be larger than %lld (got %lld)\n",
-                1ULL << 42, (long long) id);
+        fprintf(stderr, "\nAbsolute node IDs must not be larger than %" PRId64 " (got%" PRId64 " )\n",
+                (int64_t) 1 << 42, (int64_t) id);
         util::exit_nicely();
     }
     totalNodes++;
@@ -405,11 +408,13 @@ int node_ram_cache::set(osmid_t id, double lat, double lon, const taglist_t &) {
      * get pushed to the sparse cache if a block is sparse and ALLOC_SPARSE is set
      */
     if ( (allocStrategy & ALLOC_DENSE) > 0 ) {
-        return set_dense(id, ramNode(lon, lat));
+        set_dense(id, ramNode(lon, lat));
+    } else if ( (allocStrategy & ALLOC_SPARSE) > 0 ) {
+        set_sparse(id, ramNode(lon, lat));
+    } else {
+        // Command line options always have ALLOC_DENSE | ALLOC_SPARSE
+        throw std::logic_error((boost::format("Unexpected cache strategy in node_ram_cache::set with allocStrategy %1%") % allocStrategy).str());
     }
-    if ( (allocStrategy & ALLOC_SPARSE) > 0 )
-        return set_sparse(id, ramNode(lon, lat));
-    return 1;
 }
 
 int node_ram_cache::get(osmNode *out, osmid_t id) {
diff --git a/node-ram-cache.hpp b/node-ram-cache.hpp
index 94f255d..7c47f45 100644
--- a/node-ram-cache.hpp
+++ b/node-ram-cache.hpp
@@ -9,13 +9,15 @@
 #define NODE_RAM_CACHE_H
 
 #include "config.h"
-#include "osmtypes.hpp"
 
-#include <cstddef>
 #include <climits>
-#include <stdint.h>
+#include <cstddef>
+#include <cstdint>
+
 #include <boost/noncopyable.hpp>
 
+#include "osmtypes.hpp"
+
 #define ALLOC_SPARSE 1
 #define ALLOC_DENSE 2
 #define ALLOC_DENSE_CHUNK 4
@@ -26,7 +28,7 @@
  *
  * If FIXED_POINT is enabled, it uses internally a more efficient
  * representation as integer.
- */ 
+ */
 class ramNode {
 public:
 #ifdef FIXED_POINT
@@ -61,14 +63,14 @@ private:
     int _lon;
     int _lat;
 
-    int dbl2fix(const double x) const { return x * scale + 0.4; }
+    int dbl2fix(const double x) const { return (int) (x * scale + 0.4); }
     double fix2dbl(const int x) const { return (double)x / scale; }
 #else
 public:
     ramNode() : _lat(NAN), _lon(NAN) {}
-    ramNode(double _lon, double _lat) : _lon(lon), _lat(lat) {}
+    ramNode(double lon, double lat) : _lon(lon), _lat(lat) {}
 
-    bool is_valid() const ( return !std::isnan(_lon); }
+    bool is_valid() const { return !std::isnan(_lon); }
     double lon() const { return _lon; }
     double lat() const { return _lat; }
 private:
@@ -85,7 +87,7 @@ struct ramNodeID {
 
 class ramNodeBlock {
 public:
-    ramNodeBlock() : nodes(NULL), block_offset(-1), _used(0) {}
+    ramNodeBlock() : nodes(nullptr), block_offset(-1), _used(0) {}
 
     void set_dirty() { _used |= 1; }
     bool dirty() const { return _used & 1; }
@@ -107,14 +109,14 @@ struct node_ram_cache : public boost::noncopyable
     node_ram_cache(int strategy, int cacheSizeMB, int fixpointscale);
     ~node_ram_cache();
 
-    int set(osmid_t id, double lat, double lon, const taglist_t &tags);
+    void set(osmid_t id, double lat, double lon, const taglist_t &tags);
     int get(osmNode *out, osmid_t id);
 
 private:
     void percolate_up( int pos );
     ramNode *next_chunk();
-    int set_sparse(osmid_t id, const ramNode &coord);
-    int set_dense(osmid_t id, const ramNode& coord);
+    void set_sparse(osmid_t id, const ramNode &coord);
+    void set_dense(osmid_t id, const ramNode& coord);
     int get_sparse(osmNode *out, osmid_t id);
     int get_dense(osmNode *out, osmid_t id);
 
@@ -136,7 +138,7 @@ private:
 
     int64_t cacheUsed, cacheSize;
     osmid_t storedNodes, totalNodes;
-    int nodesCacheHits, nodesCacheLookups;
+    long nodesCacheHits, nodesCacheLookups;
 
     int warn_node_order;
 };
diff --git a/options.cpp b/options.cpp
index 8c2ed03..6ee3c56 100644
--- a/options.cpp
+++ b/options.cpp
@@ -1,6 +1,5 @@
 #include "options.hpp"
 #include "sprompt.hpp"
-#include "parse.hpp"
 
 #include <getopt.h>
 #ifdef HAVE_LIBGEN_H
@@ -12,6 +11,7 @@
 #include <string.h>
 #include <stdexcept>
 #include <sstream>
+#include <thread> // for number of threads
 #include <boost/format.hpp>
 
 namespace
@@ -29,7 +29,6 @@ namespace
         {"prefix",   1, 0, 'p'},
         {"proj",     1, 0, 'E'},
         {"merc",     0, 0, 'm'},
-        {"utf8-sanitize", 0, 0, 'u'},
         {"cache",    1, 0, 'C'},
         {"username", 1, 0, 'U'},
         {"password", 0, 0, 'W'},
@@ -63,6 +62,7 @@ namespace
         {"flat-nodes",1,0,209},
         {"exclude-invalid-polygon",0,0,210},
         {"tag-transform-script",1,0,212},
+        {"reproject-area",0,0,213},
         {0, 0, 0, 0}
     };
 
@@ -124,10 +124,6 @@ namespace
                         column that contains all name:xx tags\n\
           --hstore-add-index    Add index to hstore column.\n\
     \n\
-    Obsolete options:\n\
-       -u|--utf8-sanitize   Repair bad UTF8 input data (present in planet\n\
-                        dumps prior to August 2007). Adds about 10% overhead.\n\
-    \n\
     Performance options:\n\
        -i|--tablespace-index    The name of the PostgreSQL tablespace where\n\
                         all indexes will be created.\n\
@@ -178,19 +174,17 @@ namespace
                         Must be specified as: minlon,minlat,maxlon,maxlat\n\
                         e.g. --bbox -0.5,51.25,0.5,51.75\n\
        -p|--prefix      Prefix for table names (default planet_osm)\n\
-       -r|--input-reader    Input frontend.\n\
-                        libxml2   - Parse XML using libxml2. (default)\n");
-    #ifdef BUILD_READER_PBF
-        printf("\
-                        pbf       - OSM binary format.\n");
-    #endif
-        printf("\
+       -r|--input-reader    Input format.\n\
+                        auto      - Detect file format. (default)\n\
+                        o5m       - Parse as o5m format.\n\
+                        xml       - Parse as OSM XML.\n\
+                        pbf       - OSM binary format.\n\
        -O|--output      Output backend.\n\
                         pgsql - Output to a PostGIS database (default)\n\
                         multi - Multiple Custom Table Output to a PostGIS \n\
                             database (requires style file for configuration)\n\
                         gazetteer - Output to a PostGIS database for Nominatim\n\
-                        null - No output. Useful for testing\n");
+                        null - No output. Useful for testing. Still creates tables if --slim is specified.\n");
     #ifdef HAVE_LUA
         printf("\
           --tag-transform-script  Specify a lua script to handle tag filtering and normalisation\n\
@@ -208,6 +202,7 @@ namespace
                         By default natural=coastline tagged data will be discarded\n\
                         because renderers usually have shape files for them.\n\
           --exclude-invalid-polygon   do not import polygons with invalid geometries.\n\
+          --reproject-area   compute area column using spherical mercator coordinates.\n\
        -h|--help        Help information.\n\
        -v|--verbose     Verbose output.\n");
         }
@@ -233,11 +228,16 @@ namespace
 
     }
 
-std::string build_conninfo(const std::string &db,
-                           const boost::optional<std::string> &username,
-                           const boost::optional<std::string> &password,
-                           const boost::optional<std::string> &host,
-                           const std::string &port)
+} // anonymous namespace
+
+database_options_t::database_options_t():
+    db("gis"), username(boost::none), host(boost::none),
+    password(boost::none), port(boost::none)
+{
+
+}
+
+std::string database_options_t::conninfo() const
 {
     std::ostringstream out;
 
@@ -252,39 +252,42 @@ std::string build_conninfo(const std::string &db,
     if (host) {
         out << " host='" << *host << "'";
     }
-    out << " port='" << port << "'";
+    if (port) {
+        out << " port='" << *port << "'";
+    }
 
     return out.str();
 }
-} // anonymous namespace
-
 
 options_t::options_t():
-    conninfo(""), prefix("planet_osm"), scale(DEFAULT_SCALE), projection(new reprojection(PROJ_SPHERE_MERC)), append(0), slim(0),
+    prefix("planet_osm"), scale(DEFAULT_SCALE), projection(reprojection::create_projection(PROJ_SPHERE_MERC)), append(false), slim(false),
     cache(800), tblsmain_index(boost::none), tblsslim_index(boost::none), tblsmain_data(boost::none), tblsslim_data(boost::none), style(OSM2PGSQL_DATADIR "/default.style"),
-    expire_tiles_zoom(-1), expire_tiles_zoom_min(-1), expire_tiles_filename("dirty_tiles"), hstore_mode(HSTORE_NONE), enable_hstore_index(0),
-    enable_multi(false), hstore_columns(), keep_coastlines(0), parallel_indexing(1),
+    expire_tiles_zoom(-1), expire_tiles_zoom_min(-1), expire_tiles_filename("dirty_tiles"), hstore_mode(HSTORE_NONE), enable_hstore_index(false),
+    enable_multi(false), hstore_columns(), keep_coastlines(false), parallel_indexing(true),
     #ifdef __amd64__
     alloc_chunkwise(ALLOC_SPARSE | ALLOC_DENSE),
     #else
     alloc_chunkwise(ALLOC_SPARSE),
     #endif
-    num_procs(1), droptemp(0),  unlogged(0), hstore_match_only(0), flat_node_cache_enabled(0), excludepoly(0), flat_node_file(boost::none),
+    droptemp(false),  unlogged(false), hstore_match_only(false), flat_node_cache_enabled(false), excludepoly(false), reproject_area(false), flat_node_file(boost::none),
     tag_transform_script(boost::none), tag_transform_node_func(boost::none), tag_transform_way_func(boost::none),
     tag_transform_rel_func(boost::none), tag_transform_rel_mem_func(boost::none),
-    create(0), sanitize(0), long_usage_bool(0), pass_prompt(0), db("gis"), username(boost::none), host(boost::none),
-    password(boost::none), port("5432"), output_backend("pgsql"), input_reader("auto"), bbox(boost::none), extra_attributes(0), verbose(0)
+    create(false), long_usage_bool(false), pass_prompt(false),  output_backend("pgsql"), input_reader("auto"), bbox(boost::none),
+    extra_attributes(false), verbose(false)
 {
-
+    num_procs = std::thread::hardware_concurrency();
+    if (num_procs < 1) {
+        fprintf(stderr, "WARNING: unable to detect number of hardware threads supported!\n");
+        num_procs = 1;
+    }
 }
 
 options_t::~options_t()
 {
 }
 
-options_t options_t::parse(int argc, char *argv[])
+options_t::options_t(int argc, char *argv[]): options_t()
 {
-    options_t options;
     const char *temparg;
     int c;
 
@@ -293,166 +296,160 @@ options_t options_t::parse(int argc, char *argv[])
     // errors - setting it to zero seems to work, though. see
     // http://stackoverflow.com/questions/15179963/is-it-possible-to-repeat-getopt#15179990
     optind = 0;
-    while(-1 != (c = getopt_long(argc, argv, short_options, long_options, NULL))) {
+    while(-1 != (c = getopt_long(argc, argv, short_options, long_options, nullptr))) {
 
         //handle the current arg
         switch (c) {
         case 'a':
-            options.append = 1;
+            append = true;
             break;
         case 'b':
-            options.bbox = optarg;
+            bbox = optarg;
             break;
         case 'c':
-            options.create = 1;
+            create = true;
             break;
         case 'v':
-            options.verbose = 1;
+            verbose = true;
             break;
         case 's':
-            options.slim = 1;
+            slim = true;
             break;
         case 'K':
-            options.keep_coastlines = 1;
-            break;
-        case 'u':
-            options.sanitize = 1;
+            keep_coastlines = true;
             break;
         case 'l':
-            options.projection.reset(new reprojection(PROJ_LATLONG));
+            projection.reset(reprojection::create_projection(PROJ_LATLONG));
             break;
         case 'm':
-            options.projection.reset(new reprojection(PROJ_SPHERE_MERC));
+            projection.reset(reprojection::create_projection(PROJ_SPHERE_MERC));
             break;
         case 'E':
-            options.projection.reset(new reprojection(-atoi(optarg)));
+            projection.reset(reprojection::create_projection(atoi(optarg)));
             break;
         case 'p':
-            options.prefix = optarg;
+            prefix = optarg;
             break;
         case 'd':
-            options.db = optarg;
+            database_options.db = optarg;
             break;
         case 'C':
-            options.cache = atoi(optarg);
+            cache = atoi(optarg);
             break;
         case 'U':
-            options.username = optarg;
+            database_options.username = optarg;
             break;
         case 'W':
-            options.pass_prompt = 1;
+            pass_prompt = true;
             break;
         case 'H':
-            options.host = optarg;
+            database_options.host = optarg;
             break;
         case 'P':
-            options.port = optarg;
+            database_options.port = optarg;
             break;
         case 'S':
-            options.style = optarg;
+            style = optarg;
             break;
         case 'i':
-            options.tblsmain_index = options.tblsslim_index = optarg;
+            tblsmain_index = tblsslim_index = optarg;
             break;
         case 200:
-            options.tblsslim_data = optarg;
+            tblsslim_data = optarg;
             break;
         case 201:
-            options.tblsslim_index = optarg;
+            tblsslim_index = optarg;
             break;
         case 202:
-            options.tblsmain_data = optarg;
+            tblsmain_data = optarg;
             break;
         case 203:
-            options.tblsmain_index = optarg;
+            tblsmain_index = optarg;
             break;
         case 'e':
-            options.expire_tiles_zoom_min = atoi(optarg);
+            expire_tiles_zoom_min = atoi(optarg);
             temparg = strchr(optarg, '-');
             if (temparg)
-                options.expire_tiles_zoom = atoi(temparg + 1);
-            if (options.expire_tiles_zoom < options.expire_tiles_zoom_min)
-                options.expire_tiles_zoom = options.expire_tiles_zoom_min;
+                expire_tiles_zoom = atoi(temparg + 1);
+            if (expire_tiles_zoom < expire_tiles_zoom_min)
+                expire_tiles_zoom = expire_tiles_zoom_min;
             break;
         case 'o':
-            options.expire_tiles_filename = optarg;
+            expire_tiles_filename = optarg;
             break;
         case 'O':
-            options.output_backend = optarg;
+            output_backend = optarg;
             break;
         case 'x':
-            options.extra_attributes = 1;
+            extra_attributes = true;
             break;
         case 'k':
-            if (options.hstore_mode != HSTORE_NONE) {
+            if (hstore_mode != HSTORE_NONE) {
                 throw std::runtime_error("You can not specify both --hstore (-k) and --hstore-all (-j)\n");
             }
-            options.hstore_mode = HSTORE_NORM;
+            hstore_mode = HSTORE_NORM;
             break;
         case 208:
-            options.hstore_match_only = 1;
+            hstore_match_only = true;
             break;
         case 'j':
-            if (options.hstore_mode != HSTORE_NONE) {
+            if (hstore_mode != HSTORE_NONE) {
                 throw std::runtime_error("You can not specify both --hstore (-k) and --hstore-all (-j)\n");
             }
-            options.hstore_mode = HSTORE_ALL;
+            hstore_mode = HSTORE_ALL;
             break;
         case 'z':
-            options.hstore_columns.push_back(optarg);
+            hstore_columns.push_back(optarg);
             break;
         case 'G':
-            options.enable_multi = true;
+            enable_multi = true;
             break;
         case 'r':
-            options.input_reader = optarg;
+            input_reader = optarg;
             break;
         case 'h':
-            options.long_usage_bool = 1;
+            long_usage_bool = true;
             break;
         case 'I':
-#ifdef HAVE_PTHREAD
-            options.parallel_indexing = 0;
-#endif
+            parallel_indexing = false;
             break;
         case 204:
             if (strcmp(optarg, "dense") == 0)
-                options.alloc_chunkwise = ALLOC_DENSE;
+                alloc_chunkwise = ALLOC_DENSE;
             else if (strcmp(optarg, "chunk") == 0)
-                options.alloc_chunkwise = ALLOC_DENSE | ALLOC_DENSE_CHUNK;
+                alloc_chunkwise = ALLOC_DENSE | ALLOC_DENSE_CHUNK;
             else if (strcmp(optarg, "sparse") == 0)
-                options.alloc_chunkwise = ALLOC_SPARSE;
+                alloc_chunkwise = ALLOC_SPARSE;
             else if (strcmp(optarg, "optimized") == 0)
-                options.alloc_chunkwise = ALLOC_DENSE | ALLOC_SPARSE;
+                alloc_chunkwise = ALLOC_DENSE | ALLOC_SPARSE;
             else {
                 throw std::runtime_error((boost::format("Unrecognized cache strategy %1%.\n") % optarg).str());
             }
             break;
         case 205:
-#ifdef HAVE_FORK
-            options.num_procs = atoi(optarg);
-#else
-            fprintf(stderr, "WARNING: osm2pgsql was compiled without fork, only using one process!\n");
-#endif
+            num_procs = atoi(optarg);
             break;
         case 206:
-            options.droptemp = 1;
+            droptemp = true;
             break;
         case 207:
-            options.unlogged = 1;
+            unlogged = true;
             break;
         case 209:
-            options.flat_node_cache_enabled = 1;
-            options.flat_node_file = optarg;
+            flat_node_cache_enabled = true;
+            flat_node_file = optarg;
             break;
         case 210:
-            options.excludepoly = 1;
+            excludepoly = true;
             break;
         case 211:
-            options.enable_hstore_index = 1;
+            enable_hstore_index = true;
             break;
         case 212:
-            options.tag_transform_script = optarg;
+            tag_transform_script = optarg;
+            break;
+        case 213:
+            reproject_area = true;
             break;
         case 'V':
             exit (EXIT_SUCCESS);
@@ -465,8 +462,9 @@ options_t options_t::parse(int argc, char *argv[])
     } //end while
 
     //they were looking for usage info
-    if (options.long_usage_bool) {
-        long_usage(argv[0], options.verbose);
+    if (long_usage_bool) {
+        long_usage(argv[0], verbose);
+        return;
     }
 
     //we require some input files!
@@ -476,73 +474,74 @@ options_t options_t::parse(int argc, char *argv[])
 
     //get the input files
     while (optind < argc) {
-        options.input_files.push_back(std::string(argv[optind]));
+        input_files.push_back(std::string(argv[optind]));
         optind++;
     }
 
-    if (options.append && options.create) {
+    check_options();
+
+    if (pass_prompt) {
+        char *prompt = simple_prompt("Password:", 100, 0);
+        if (prompt == nullptr) {
+            database_options.password = boost::none;
+        } else {
+            database_options.password = std::string(prompt);
+        }
+    }
+
+
+    //NOTE: this is hugely important if you set it inappropriately and are are caching nodes
+    //you could get overflow when working with larger coordinates (mercator) and larger scales
+    scale = (projection->target_latlon()) ? 10000000 : 100;
+}
+
+void options_t::check_options()
+{
+    if (append && create) {
         throw std::runtime_error("--append and --create options can not be used at the same time!\n");
     }
 
-    if (options.append && !options.slim) {
+    if (append && !slim) {
         throw std::runtime_error("--append can only be used with slim mode!\n");
     }
 
-    if (options.droptemp && !options.slim) {
+    if (droptemp && !slim) {
         throw std::runtime_error("--drop only makes sense with --slim.\n");
     }
 
-    if (options.unlogged && !options.create) {
+    if (unlogged && !create) {
         fprintf(stderr, "Warning: --unlogged only makes sense with --create; ignored.\n");
-        options.unlogged = 0;
+        unlogged = false;
     }
 
-    if (options.hstore_mode == HSTORE_NONE && options.hstore_columns.size() == 0 && options.hstore_match_only) {
+    if (hstore_mode == HSTORE_NONE && hstore_columns.size() == 0 && hstore_match_only) {
         fprintf(stderr, "Warning: --hstore-match-only only makes sense with --hstore, --hstore-all, or --hstore-column; ignored.\n");
-        options.hstore_match_only = 0;
+        hstore_match_only = false;
     }
 
-    if (options.enable_hstore_index && options.hstore_mode == HSTORE_NONE && options.hstore_columns.size() == 0) {
+    if (enable_hstore_index && hstore_mode == HSTORE_NONE && hstore_columns.size() == 0) {
         fprintf(stderr, "Warning: --hstore-add-index only makes sense with hstore enabled.\n");
-        options.enable_hstore_index = 0;
+        enable_hstore_index = false;
     }
 
-    if (options.cache < 0)
-        options.cache = 0;
+    if (cache < 0) {
+        cache = 0;
+        fprintf(stderr, "WARNING: ram cache cannot be negative. Using 0 instead.\n\n");
+    }
 
-    if (options.cache == 0) {
+    if (cache == 0) {
         fprintf(stderr, "WARNING: ram cache is disabled. This will likely slow down processing a lot.\n\n");
     }
-    if (sizeof(int*) == 4 && options.slim != 1) {
+
+    if (num_procs < 1) {
+        num_procs = 1;
+        fprintf(stderr, "WARNING: Must use at least 1 process.\n\n");
+    }
+
+    if (sizeof(int*) == 4 && !slim) {
         fprintf(stderr, "\n!! You are running this on 32bit system, so at most\n");
         fprintf(stderr, "!! 3GB of RAM can be used. If you encounter unexpected\n");
         fprintf(stderr, "!! exceptions during import, you should try running in slim\n");
         fprintf(stderr, "!! mode using parameter -s.\n");
     }
-
-    if (options.pass_prompt) {
-        char *prompt = simple_prompt("Password:", 100, 0);
-        if (prompt == NULL) {
-            options.password = boost::none;
-        } else {
-            options.password = std::string(prompt);
-        }
-    } else {
-        char *pgpass = getenv("PGPASS");
-        if (pgpass == NULL) {
-            options.password = boost::none;
-        } else {
-            options.password = std::string(pgpass);
-        }
-    }
-
-    if (options.num_procs < 1)
-        options.num_procs = 1;
-
-    //NOTE: this is hugely important if you set it inappropriately and are are caching nodes
-    //you could get overflow when working with larger coordinates (mercator) and larger scales
-    options.scale = (options.projection->get_proj_id() == PROJ_LATLONG) ? 10000000 : 100;
-    options.conninfo = build_conninfo(options.db, options.username, options.password, options.host, options.port);
-
-    return options;
 }
diff --git a/options.hpp b/options.hpp
index f0abf97..f4e2fc3 100644
--- a/options.hpp
+++ b/options.hpp
@@ -6,7 +6,7 @@
 
 #include <vector>
 #include <string>
-#include <boost/shared_ptr.hpp>
+#include <memory>
 #include <boost/optional.hpp>
 
 /* Variants for generation of hstore column */
@@ -20,68 +20,92 @@
 /* Scale is chosen such that 40,000 * SCALE < 2^32          */
 enum { DEFAULT_SCALE = 100 };
 
-//TODO: GO THROUGH AND UPDATE TO BOOL WHERE MEMBER DENOTES ONLY ON OR OFF OPTION
+/**
+ * Database options, not specific to a table
+ */
+class database_options_t {
+public:
+    database_options_t();
+    std::string db;
+    boost::optional<std::string> username;
+    boost::optional<std::string> host;
+    boost::optional<std::string> password;
+    boost::optional<std::string> port;
+
+    std::string conninfo() const;
+};
+
+/**
+ * Structure for storing command-line and other options
+ */
 struct options_t {
 public:
-    /* construct with sensible defaults */
+  // fixme: bring back old comment
     options_t();
+    /**
+     * Parse the options from the command line
+     */
+    options_t(int argc, char *argv[]);
     virtual ~options_t();
 
-    static options_t parse(int argc, char *argv[]);
-
-    std::string conninfo; /* Connection info string */
-    std::string prefix; /* prefix for table names */
-    int scale; /* scale for converting coordinates to fixed point */
-    boost::shared_ptr<reprojection> projection; /* SRS of projection */
-    bool append; /* Append to existing data */
-    bool slim; /* In slim mode */
-    int cache; /* Memory usable for cache in MB */
-    boost::optional<std::string> tblsmain_index; /* Pg Tablespace to store indexes on main tables (no default TABLESPACE)*/
-    boost::optional<std::string> tblsslim_index; /* Pg Tablespace to store indexes on slim tables (no default TABLESPACE)*/
-    boost::optional<std::string> tblsmain_data; /* Pg Tablespace to store main tables (no default TABLESPACE)*/
-    boost::optional<std::string> tblsslim_data; /* Pg Tablespace to store slim tables (no default TABLESPACE)*/
-    std::string style; /* style file to use */
-    int expire_tiles_zoom; /* Zoom level for tile expiry list */
-    int expire_tiles_zoom_min; /* Minimum zoom level for tile expiry list */
-    std::string expire_tiles_filename; /* File name to output expired tiles list to */
-    int hstore_mode; /* add an additional hstore column with objects key/value pairs */
-    int enable_hstore_index; /* add an index on the hstore column */
-    bool enable_multi; /* Output multi-geometries intead of several simple geometries */
-    std::vector<std::string> hstore_columns; /* list of columns that should be written into their own hstore column */
-    int keep_coastlines;
-    int parallel_indexing;
+    std::string prefix; ///< prefix for table names
+    int scale; ///< scale for converting coordinates to fixed point
+    std::shared_ptr<reprojection> projection; ///< SRS of projection
+    bool append; ///< Append to existing data
+    bool slim; ///< In slim mode
+    int cache; ///< Memory usable for cache in MB
+    boost::optional<std::string> tblsmain_index; ///< Pg Tablespace to store indexes on main tables (no default TABLESPACE)
+    boost::optional<std::string> tblsslim_index; ///< Pg Tablespace to store indexes on slim tables (no default TABLESPACE)
+    boost::optional<std::string> tblsmain_data; ///< Pg Tablespace to store main tables (no default TABLESPACE)
+    boost::optional<std::string> tblsslim_data; ///< Pg Tablespace to store slim tables (no default TABLESPACE)
+    std::string style; ///< style file to use
+    int expire_tiles_zoom; ///< Zoom level for tile expiry list
+    int expire_tiles_zoom_min; ///< Minimum zoom level for tile expiry list
+    std::string expire_tiles_filename; ///< File name to output expired tiles list to
+    int hstore_mode; ///< add an additional hstore column with objects key/value pairs, and what type of hstore column
+    bool enable_hstore_index; ///< add an index on the hstore column
+    bool enable_multi; ///< Output multi-geometries intead of several simple geometries
+    std::vector<std::string> hstore_columns; ///< list of columns that should be written into their own hstore column
+    bool keep_coastlines;
+    bool parallel_indexing;
     int alloc_chunkwise;
     int num_procs;
-    int droptemp; /* drop slim mode temp tables after act */
-    int unlogged; /* use unlogged tables where possible */
-    int hstore_match_only; /* only copy rows that match an explicitly listed key */
-    int flat_node_cache_enabled;
-    int excludepoly;
+    bool droptemp; ///< drop slim mode temp tables after act
+    bool unlogged; ///< use unlogged tables where possible
+    bool hstore_match_only; ///< only copy rows that match an explicitly listed key
+    bool flat_node_cache_enabled;
+    bool excludepoly;
+    bool reproject_area;
     boost::optional<std::string> flat_node_file;
+    /**
+     * these options allow you to control the name of the
+     * Lua functions which get called in the tag transform
+     * script. this is mostly useful in with the "multi"
+     * output so that a single script file can be used.
+     */
     boost::optional<std::string> tag_transform_script,
-        tag_transform_node_func,    // these options allow you to control the name of the
-        tag_transform_way_func,     // Lua functions which get called in the tag transform
-        tag_transform_rel_func,     // script. this is mostly useful in with the "multi"
-        tag_transform_rel_mem_func; // output so that a single script file can be used.
+        tag_transform_node_func,
+        tag_transform_way_func,
+        tag_transform_rel_func,
+        tag_transform_rel_mem_func;
 
-    int create;
-    int sanitize;
-    int long_usage_bool;
-    int pass_prompt;
-    std::string db;
-    boost::optional<std::string> username;
-    boost::optional<std::string> host;
-    boost::optional<std::string> password;
-    std::string port;
-    std::string output_backend ;
+    bool create;
+    bool long_usage_bool;
+    bool pass_prompt;
+
+    database_options_t database_options;
+    std::string output_backend;
     std::string input_reader;
     boost::optional<std::string> bbox;
-    int extra_attributes;
-    int verbose;
+    bool extra_attributes;
+    bool verbose;
 
     std::vector<std::string> input_files;
 private:
-
+    /**
+     * Check input options for sanity
+     */
+    void check_options();
 };
 
 #endif
diff --git a/osm2pgsql.cpp b/osm2pgsql.cpp
index aa5674e..aff39b8 100644
--- a/osm2pgsql.cpp
+++ b/osm2pgsql.cpp
@@ -27,7 +27,7 @@
 #include "osmtypes.hpp"
 #include "reprojection.hpp"
 #include "options.hpp"
-#include "parse.hpp"
+#include "parse-osmium.hpp"
 #include "middle.hpp"
 #include "output.hpp"
 #include "osmdata.hpp"
@@ -43,58 +43,31 @@
 #include <libpq-fe.h>
 #include <boost/format.hpp>
 
-void check_db(const char* conninfo, const int unlogged)
-{
-    PGconn *sql_conn = PQconnectdb(conninfo);
-
-    //make sure you can connect
-    if (PQstatus(sql_conn) != CONNECTION_OK) {
-        throw std::runtime_error((boost::format("Error: Connection to database failed: %1%\n") % PQerrorMessage(sql_conn)).str());
-    }
-
-    //make sure unlogged it is supported by your database if you want it
-    if (unlogged && PQserverVersion(sql_conn) < 90100) {
-        throw std::runtime_error((
-            boost::format("Error: --unlogged works only with PostgreSQL 9.1 and above, but\n you are using PostgreSQL %1%.%2%.%3%.\n")
-            % (PQserverVersion(sql_conn) / 10000)
-            % ((PQserverVersion(sql_conn) / 100) % 100)
-            % (PQserverVersion(sql_conn) % 100)).str());
-    }
-
-    PQfinish(sql_conn);
-}
-
 int main(int argc, char *argv[])
 {
-    fprintf(stderr, "osm2pgsql SVN version %s (%lubit id space)\n\n", VERSION, 8 * sizeof(osmid_t));
+    fprintf(stderr, "osm2pgsql SVN version %s (%zu bit id space)\n\n", VERSION, 8 * sizeof(osmid_t));
     try
     {
         //parse the args into the different options members
-        options_t options = options_t::parse(argc, argv);
+        options_t options = options_t(argc, argv);
         if(options.long_usage_bool)
             return 0;
 
-        //setup the front (input)
-        parse_delegate_t parser(options.extra_attributes, options.bbox, options.projection);
-
         //setup the middle
-        boost::shared_ptr<middle_t> middle = middle_t::create_middle(options.slim);
+        std::shared_ptr<middle_t> middle = middle_t::create_middle(options.slim);
 
         //setup the backend (output)
-        std::vector<boost::shared_ptr<output_t> > outputs = output_t::create_outputs(middle.get(), options);
+        std::vector<std::shared_ptr<output_t> > outputs = output_t::create_outputs(middle.get(), options);
 
         //let osmdata orchestrate between the middle and the outs
         osmdata_t osmdata(middle, outputs);
 
-        //check the database
-        check_db(options.conninfo.c_str(), options.unlogged);
-
         fprintf(stderr, "Using projection SRS %d (%s)\n",
-                options.projection->project_getprojinfo()->srs,
-                options.projection->project_getprojinfo()->descr );
+                options.projection->target_srs(),
+                options.projection->target_desc());
 
         //start it up
-        time_t overall_start = time(NULL);
+        time_t overall_start = time(nullptr);
         osmdata.start();
 
         /* Processing
@@ -102,24 +75,30 @@ int main(int argc, char *argv[])
          * tables. Not all ways can be handled before relations are processed, so they're
          * set as pending, to be handled in the next stage.
          */
+        parse_stats_t stats;
         //read in the input files one by one
-        for(std::vector<std::string>::const_iterator filename = options.input_files.begin(); filename != options.input_files.end(); ++filename)
-        {
+        for (auto const filename : options.input_files) {
             //read the actual input
-            fprintf(stderr, "\nReading in file: %s\n", filename->c_str());
-            time_t start = time(NULL);
-            if (parser.streamFile(options.input_reader.c_str(), filename->c_str(), options.sanitize, &osmdata) != 0)
-                util::exit_nicely();
-            fprintf(stderr, "  parse time: %ds\n", (int)(time(NULL) - start));
+            fprintf(stderr, "\nReading in file: %s\n", filename.c_str());
+            time_t start = time(nullptr);
+
+            parse_osmium_t parser(options.extra_attributes,
+                                  options.bbox, options.projection.get(),
+                                  options.append, &osmdata);
+            parser.stream_file(filename, options.input_reader);
+
+            stats.update(parser.stats());
+
+            fprintf(stderr, "  parse time: %ds\n", (int)(time(nullptr) - start));
         }
 
         //show stats
-        parser.printSummary();
+        stats.print_summary();
 
         //Process pending ways, relations, cluster, and create indexes
         osmdata.stop();
 
-        fprintf(stderr, "\nOsm2pgsql took %ds overall\n", (int)(time(NULL) - overall_start));
+        fprintf(stderr, "\nOsm2pgsql took %ds overall\n", (int)(time(nullptr) - overall_start));
 
         return 0;
     }//something went wrong along the way
diff --git a/osm2pgsql.spec.in b/osm2pgsql.spec.in
deleted file mode 100644
index 35226c7..0000000
--- a/osm2pgsql.spec.in
+++ /dev/null
@@ -1,96 +0,0 @@
-
-%define svn @SVN@
-
-Summary: Imports map data from www.OpenStreetMap.org to a PostgresSQL database
-Name: 	 @PACKAGE@
-Group:	 Applications/Text
-Version: @VERSION@
-Release: 1.%{svn}%{?dist}
-
-License: GPL
-URL:     http://svn.openstreetmap.org/applications/utils/export/osm2pgsql
-Source0: %{name}-%{version}.tar.bz2
-Source1: osm2pgsql-svn.sh
-BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) 
-
-BuildRequires: geos-devel
-BuildRequires: libxml2-devel
-BuildRequires: postgresql-devel
-BuildRequires: bzip2-devel
-BuildRequires: proj-devel
-
-%description
-Processes the planet file from the communtiy mapping project at
-http://www.openstreetmap.org. The map data is converted from XML to a
-database stored in PostgreSQL with PostGIS geospatial extentions. This
-database may then be used to render maps with Mapnik or for other
-geospatial analysis.
-
-%prep
-%setup -q  -n %{name}
-
-
-%build
-
-export CFLAGS="$RPM_OPT_FLAGS"
-export CXXFLAGS="$RPM_OPT_FLAGS"
-
-make all
-
-
-%install
-rm -rf $RPM_BUILD_ROOT
-install -D -p osm2pgsql $RPM_BUILD_ROOT/usr/bin/osm2pgsql
-
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-
-%files
-%defattr(-,root,root)
-%doc README
-%{_bindir}/osm2pgsql
-
-
-%changelog
-* Sun Nov 23 2008 Keith Sharp <kms at passback.co.uk> - 0.55-1.20081123
-- Fixed case of README.txt filename in Makefile
-- Fixed case of README.txt filename in osm2pgsql.spec.in
-- Fixed make clean to remove generated osm2pgsql.spec file
-
-* Mon Sep  3 2007 Jon Burgess <jburgess777 at googlemail.com> - 0.06-1.20070903
-- Add several command line options and help text
-- "--append" mode which imports extra data into the DB
-- "--database" to specify the Postgresql DB name
-- "--slim" to select the middle_ram code
-- Multiple files can be read sequentially, e.g. lots of tiger county.osm files
-
-* Sun Aug 19 2007 Jon Burgess <jburgess777 at googlemail.com> - 0.04-1.20070812
-- Allow polygon data types to appear as linestring if not closed (was broken by previous change)
-- Handle exception when finding an interior point of a complex polygon geometry
-- Add in a text cache for key/value pairs
-- Switch to 65k blocks for object store
-- Exclude source= during import
-- The above changes save around 10% memory usage during a planet import
-- Push leisure= polygons down to improve rendering
-
-* Sun Aug 19 2007 Jon Burgess <jburgess777 at googlemail.com> - 0.3-1.20070812
-- Handle polygons with holes properly
-- Export a couple more keys
-
-* Sun Aug 12 2007 Jon Burgess <jburgess777 at googlemail.com> - 0.2-1.20070812
-- Added rpm build target to SVN osm2pgsql source
-- Enhanced middle-ram to remove hard coded maximum IDs 
-- Support negative IDs in middle-ram
-- Replace centroid with interior to cope with unusual pareking polygons
- 
-* Tue Jul 31 2007 Keith Sharp <kms at passback.co.uk> 0.1-2.20070728svn
-- Fixed BuidlRequires so that Mock builds work.
-
-* Sat Jul 28 2007 Keith Sharp <kms at passback.co.uk> 0.1-1.20070728svn
-- Updated to latest SVN, now includes UTF8Sanitize functioanlity
-- Building on F7 now has latest GEOS
-
-* Fri Mar 16 2007 Keith Sharp <kms at passback.co.uk> 0.1-1.20070316svn
-- Initial build
diff --git a/osmdata.cpp b/osmdata.cpp
index 95c25b5..f3c0675 100644
--- a/osmdata.cpp
+++ b/osmdata.cpp
@@ -1,25 +1,22 @@
-#include "osmdata.hpp"
-#include "output.hpp"
-#include "middle.hpp"
-#include "node-ram-cache.hpp"
-
-#include <boost/foreach.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/thread/thread.hpp>
-#include <boost/unordered_map.hpp>
-#include <boost/thread.hpp>
-#include <boost/version.hpp>
-
+#include <cstdio>
+#include <functional>
+#include <future>
+#include <mutex>
 #include <stdexcept>
 #include <utility>
-#include <cstdio>
+#include <vector>
+
+#include "middle.hpp"
+#include "node-ram-cache.hpp"
+#include "osmdata.hpp"
+#include "output.hpp"
 
-osmdata_t::osmdata_t(boost::shared_ptr<middle_t> mid_, const boost::shared_ptr<output_t>& out_): mid(mid_)
+osmdata_t::osmdata_t(std::shared_ptr<middle_t> mid_, const std::shared_ptr<output_t>& out_): mid(mid_)
 {
     outs.push_back(out_);
 }
 
-osmdata_t::osmdata_t(boost::shared_ptr<middle_t> mid_, const std::vector<boost::shared_ptr<output_t> > &outs_)
+osmdata_t::osmdata_t(std::shared_ptr<middle_t> mid_, const std::vector<std::shared_ptr<output_t> > &outs_)
     : mid(mid_), outs(outs_)
 {
     if (outs.empty()) {
@@ -39,7 +36,7 @@ int osmdata_t::node_add(osmid_t id, double lat, double lon, const taglist_t &tag
     ramNode n(lon, lat);
 
     int status = 0;
-    BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
+    for (auto& out: outs) {
         status |= out->node_add(id, n.lat(), n.lon(), tags);
     }
     return status;
@@ -49,7 +46,7 @@ int osmdata_t::way_add(osmid_t id, const idlist_t &nodes, const taglist_t &tags)
     mid->ways_set(id, nodes, tags);
 
     int status = 0;
-    BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
+    for (auto& out: outs) {
         status |= out->way_add(id, nodes, tags);
     }
     return status;
@@ -59,7 +56,7 @@ int osmdata_t::relation_add(osmid_t id, const memberlist_t &members, const tagli
     mid->relations_set(id, members, tags);
 
     int status = 0;
-    BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
+    for (auto& out: outs) {
         status |= out->relation_add(id, members, tags);
     }
     return status;
@@ -75,7 +72,7 @@ int osmdata_t::node_modify(osmid_t id, double lat, double lon, const taglist_t &
     ramNode n(lon, lat);
 
     int status = 0;
-    BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
+    for (auto& out: outs) {
         status |= out->node_modify(id, n.lat(), n.lon(), tags);
     }
 
@@ -91,7 +88,7 @@ int osmdata_t::way_modify(osmid_t id, const idlist_t &nodes, const taglist_t &ta
     slim->ways_set(id, nodes, tags);
 
     int status = 0;
-    BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
+    for (auto& out: outs) {
         status |= out->way_modify(id, nodes, tags);
     }
 
@@ -107,7 +104,7 @@ int osmdata_t::relation_modify(osmid_t id, const memberlist_t &members, const ta
     slim->relations_set(id, members, tags);
 
     int status = 0;
-    BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
+    for (auto& out: outs) {
         status |= out->relation_modify(id, members, tags);
     }
 
@@ -120,7 +117,7 @@ int osmdata_t::node_delete(osmid_t id) {
     slim_middle_t *slim = dynamic_cast<slim_middle_t *>(mid.get());
 
     int status = 0;
-    BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
+    for (auto& out: outs) {
         status |= out->node_delete(id);
     }
 
@@ -133,7 +130,7 @@ int osmdata_t::way_delete(osmid_t id) {
     slim_middle_t *slim = dynamic_cast<slim_middle_t *>(mid.get());
 
     int status = 0;
-    BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
+    for (auto& out: outs) {
         status |= out->way_delete(id);
     }
 
@@ -146,7 +143,7 @@ int osmdata_t::relation_delete(osmid_t id) {
     slim_middle_t *slim = dynamic_cast<slim_middle_t *>(mid.get());
 
     int status = 0;
-    BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
+    for (auto& out: outs) {
         status |= out->relation_delete(id);
     }
 
@@ -156,7 +153,7 @@ int osmdata_t::relation_delete(osmid_t id) {
 }
 
 void osmdata_t::start() {
-    BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
+    for (auto& out: outs) {
         out->start();
     }
     mid->start(outs[0]->get_options());
@@ -169,10 +166,14 @@ namespace {
 //since the fetching from middle should be faster than the processing in each backend.
 
 struct pending_threaded_processor : public middle_t::pending_processor {
-    typedef std::vector<boost::shared_ptr<output_t> > output_vec_t;
-    typedef std::pair<boost::shared_ptr<const middle_query_t>, output_vec_t> clone_t;
-
-    static void do_jobs(output_vec_t const& outputs, pending_queue_t& queue, size_t& ids_done, boost::mutex& mutex, int append, bool ways) {
+    typedef std::vector<std::shared_ptr<output_t>> output_vec_t;
+    typedef std::pair<std::shared_ptr<const middle_query_t>, output_vec_t> clone_t;
+
+    static void do_jobs(output_vec_t const& outputs, pending_queue_t& queue, size_t& ids_done, std::mutex& mutex, int append, bool ways) {
+#ifdef _MSC_VER
+	// Avoid problems when GEOS WKT-related methods switch the locale
+        _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
+#endif
         while (true) {
             //get the job off the queue synchronously
             pending_job_t job;
@@ -200,7 +201,7 @@ struct pending_threaded_processor : public middle_t::pending_processor {
     }
 
     //starts up count threads and works on the queue
-    pending_threaded_processor(boost::shared_ptr<middle_query_t> mid, const output_vec_t& outs, size_t thread_count, size_t job_count, int append)
+    pending_threaded_processor(std::shared_ptr<middle_query_t> mid, const output_vec_t& outs, size_t thread_count, size_t job_count, int append)
         //note that we cant hint to the stack how large it should be ahead of time
         //we could use a different datastructure like a deque or vector but then
         //the outputs the enqueue jobs would need the version check for the push(_back) method
@@ -210,11 +211,11 @@ struct pending_threaded_processor : public middle_t::pending_processor {
         clones.reserve(thread_count);
         for (size_t i = 0; i < thread_count; ++i) {
             //clone the middle
-            boost::shared_ptr<const middle_query_t> mid_clone = mid->get_instance();
+            std::shared_ptr<const middle_query_t> mid_clone = mid->get_instance();
 
             //clone the outs
             output_vec_t out_clones;
-            BOOST_FOREACH(const boost::shared_ptr<output_t>& out, outs) {
+            for (const auto& out: outs) {
                 out_clones.push_back(out->clone(mid_clone.get()));
             }
 
@@ -239,21 +240,36 @@ struct pending_threaded_processor : public middle_t::pending_processor {
         fprintf(stderr, "\nGoing over pending ways...\n");
         fprintf(stderr, "\t%zu ways are pending\n", ids_queued);
         fprintf(stderr, "\nUsing %zu helper-processes\n", clones.size());
-        time_t start = time(NULL);
+        time_t start = time(nullptr);
 
 
         //make the threads and start them
+        std::vector<std::future<void>> workers;
         for (size_t i = 0; i < clones.size(); ++i) {
-            workers.create_thread(boost::bind(do_jobs, boost::cref(clones[i].second), boost::ref(queue), boost::ref(ids_done), boost::ref(mutex), append, true));
+            workers.push_back(std::async(std::launch::async,
+                                         do_jobs, std::cref(clones[i].second),
+                                         std::ref(queue), std::ref(ids_done),
+                                         std::ref(mutex), append, true));
         }
 
         //TODO: print out partial progress
 
-        //wait for them to really be done
-        workers.join_all();
+        for (auto& w: workers) {
+            try {
+                w.get();
+            } catch (...) {
+                // drain the queue, so that the other workers finish
+                mutex.lock();
+                while (!queue.empty()) {
+                    queue.pop();
+                }
+                mutex.unlock();
+                throw;
+            }
+        }
 
-        time_t finish = time(NULL);
-        fprintf(stderr, "\rFinished processing %zu ways in %i sec\n\n", ids_queued, (int)(finish - start));
+        time_t finish = time(nullptr);
+        fprintf(stderr, "\rFinished processing %zu ways in %i s\n\n", ids_queued, (int)(finish - start));
         if (finish - start > 0)
             fprintf(stderr, "%zu Pending ways took %ds at a rate of %.2f/s\n", ids_queued, (int)(finish - start),
                     ((double)ids_queued / (double)(finish - start)));
@@ -262,7 +278,7 @@ struct pending_threaded_processor : public middle_t::pending_processor {
 
         //collect all the new rels that became pending from each
         //output in each thread back to their respective main outputs
-        BOOST_FOREACH(const clone_t& clone, clones) {
+        for (const auto& clone: clones) {
             //for each clone/original output
             for(output_vec_t::const_iterator original_output = outs.begin(), clone_output = clone.second.begin();
                 original_output != outs.end() && clone_output != clone.second.end(); ++original_output, ++clone_output) {
@@ -287,20 +303,33 @@ struct pending_threaded_processor : public middle_t::pending_processor {
         fprintf(stderr, "\nGoing over pending relations...\n");
         fprintf(stderr, "\t%zu relations are pending\n", ids_queued);
         fprintf(stderr, "\nUsing %zu helper-processes\n", clones.size());
-        time_t start = time(NULL);
+        time_t start = time(nullptr);
 
         //make the threads and start them
+        std::vector<std::future<void>> workers;
         for (size_t i = 0; i < clones.size(); ++i) {
-            workers.create_thread(boost::bind(do_jobs, boost::cref(clones[i].second), boost::ref(queue), boost::ref(ids_done), boost::ref(mutex), append, false));
+            workers.push_back(std::async(std::launch::async,
+                                         do_jobs, std::cref(clones[i].second),
+                                         std::ref(queue), std::ref(ids_done),
+                                         std::ref(mutex), append, false));
         }
 
-        //TODO: print out partial progress
-
-        //wait for them to really be done
-        workers.join_all();
+        for (auto& w: workers) {
+            try {
+                w.get();
+            } catch (...) {
+                // drain the queue, so the other worker finish immediately
+                mutex.lock();
+                while (!queue.empty()) {
+                    queue.pop();
+                }
+                mutex.unlock();
+                throw;
+            }
+        }
 
-        time_t finish = time(NULL);
-        fprintf(stderr, "\rFinished processing %zu relations in %i sec\n\n", ids_queued, (int)(finish - start));
+        time_t finish = time(nullptr);
+        fprintf(stderr, "\rFinished processing %zu relations in %i s\n\n", ids_queued, (int)(finish - start));
         if (finish - start > 0)
             fprintf(stderr, "%zu Pending relations took %ds at a rate of %.2f/s\n", ids_queued, (int)(finish - start),
                     ((double)ids_queued / (double)(finish - start)));
@@ -308,7 +337,7 @@ struct pending_threaded_processor : public middle_t::pending_processor {
         ids_done = 0;
 
         //collect all expiry tree informations together into one
-        BOOST_FOREACH(const clone_t& clone, clones) {
+        for (const auto& clone: clones) {
             //for each clone/original output
             for(output_vec_t::const_iterator original_output = outs.begin(), clone_output = clone.second.begin();
                 original_output != outs.end() && clone_output != clone.second.end(); ++original_output, ++clone_output) {
@@ -324,19 +353,17 @@ private:
     //middle and output copies
     std::vector<clone_t> clones;
     output_vec_t outs; //would like to move ownership of outs to osmdata_t and middle passed to output_t instead of owned by it
-    //actual threads
-    boost::thread_group workers;
     //how many jobs do we have in the queue to start with
     size_t ids_queued;
     //appending to output that is already there (diff processing)
-    int append;
+    bool append;
     //job queue
     pending_queue_t queue;
 
     //how many ids within the job have been processed
     size_t ids_done;
     //so the threads can manage some of the shared state
-    boost::mutex mutex;
+    std::mutex mutex;
 };
 
 } // anonymous namespace
@@ -348,14 +375,14 @@ void osmdata_t::stop() {
      */
     size_t pending_count = mid->pending_count();
     mid->commit();
-    BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
+    for (auto& out: outs) {
         //TODO: each of the outs can be in parallel
         out->commit();
         pending_count += out->pending_count();
     }
 
     // should be the same for all outputs
-    const int append = outs[0]->get_options()->append;
+    const bool append = outs[0]->get_options()->append;
 
     //threaded pending processing
     pending_threaded_processor ptp(mid, outs, outs[0]->get_options()->num_procs, pending_count, append);
@@ -372,12 +399,19 @@ void osmdata_t::stop() {
         mid->iterate_relations( ptp );
     }
 
-	//Clustering, index creation, and cleanup.
-	//All the intensive parts of this are long-running PostgreSQL commands
-    boost::thread_group threads;
-    BOOST_FOREACH(boost::shared_ptr<output_t>& out, outs) {
-        threads.add_thread(new boost::thread(boost::bind( &output_t::stop, out.get() )));
+    // Clustering, index creation, and cleanup.
+    // All the intensive parts of this are long-running PostgreSQL commands
+
+    std::vector<std::future<void>> futures;
+
+    // XXX we might get too many parallel processes here
+    //     use osmium worker pool instead
+    for (auto& out: outs) {
+        futures.push_back(std::async(&output_t::stop, out.get()));
+    }
+    futures.push_back(std::async(&middle_t::stop, mid.get()));
+
+    for (auto& f: futures) {
+      f.get();
     }
-    threads.add_thread(new boost::thread(boost::bind( &middle_t::stop, mid.get() )));
-    threads.join_all();
 }
diff --git a/osmdata.hpp b/osmdata.hpp
index 460a5f5..dff7621 100644
--- a/osmdata.hpp
+++ b/osmdata.hpp
@@ -5,8 +5,8 @@
 // to get the print format specifiers in the inttypes.h header.
 #include "config.h"
 
-#include <boost/shared_ptr.hpp>
 #include <vector>
+#include <memory>
 
 #include "osmtypes.hpp"
 
@@ -15,8 +15,8 @@ struct middle_t;
 
 class osmdata_t {
 public:
-    osmdata_t(boost::shared_ptr<middle_t> mid_, const boost::shared_ptr<output_t>& out_);
-    osmdata_t(boost::shared_ptr<middle_t> mid_, const std::vector<boost::shared_ptr<output_t> > &outs_);
+    osmdata_t(std::shared_ptr<middle_t> mid_, const std::shared_ptr<output_t>& out_);
+    osmdata_t(std::shared_ptr<middle_t> mid_, const std::vector<std::shared_ptr<output_t> > &outs_);
     ~osmdata_t();
 
     void start();
@@ -35,8 +35,8 @@ public:
     int relation_delete(osmid_t id);
 
 private:
-    boost::shared_ptr<middle_t> mid;
-    std::vector<boost::shared_ptr<output_t> > outs;
+    std::shared_ptr<middle_t> mid;
+    std::vector<std::shared_ptr<output_t> > outs;
 };
 
 #endif
diff --git a/osmtypes.hpp b/osmtypes.hpp
index 0c69670..1fd6151 100644
--- a/osmtypes.hpp
+++ b/osmtypes.hpp
@@ -42,28 +42,28 @@ struct member {
 
 typedef std::vector<member> memberlist_t;
 
-struct tag {
+struct tag_t {
   std::string key;
   std::string value;
 
-  tag(const std::string &k, const std::string &v) : key(k), value(v) {}
+  tag_t(const std::string &k, const std::string &v) : key(k), value(v) {}
 };
 
 
-class taglist_t : public std::vector<tag> {
+class taglist_t : public std::vector<tag_t> {
 
-  typedef std::vector<tag> base_t;
+  typedef std::vector<tag_t> base_t;
 
 public:
-  const tag *find(const std::string &key) const { return _find(key); }
+  const tag_t *find(const std::string &key) const { return _find(key); }
 
-  tag *find(const std::string &key) {  return const_cast<tag *>(_find(key)); }
+  tag_t *find(const std::string &key) {  return const_cast<tag_t *>(_find(key)); }
 
-  size_t indexof(const std::string &key) const
+  int indexof(const std::string &key) const
   {
       for (size_t i = 0; i < size(); ++i)
           if (at(i).key == key)
-              return i;
+              return int(i);
 
       return -1;
   }
@@ -93,16 +93,27 @@ public:
     return defval;
   }
 
-  void push_dedupe(const tag& t)
+  void push_dedupe(const tag_t& t)
   {
       if (find(t.key) == 0)
           push_back(t);
   }
 
+    /** Pushes a tag onto the list, overriding an existing tag if necessary */
+    void push_override(const tag_t& t)
+    {
+        auto *tag_in_list = find(t.key);
+
+        if (tag_in_list == 0) {
+            push_back(t);
+        } else {
+            tag_in_list->value = t.value;
+        }
+    }
   bool contains(const std::string &key) const { return _find(key) != 0; }
 
 private:
-  const tag *_find(const std::string &key) const
+  const tag_t *_find(const std::string &key) const
   {
     for (base_t::const_iterator it = begin() ; it != end(); ++it)
       if (it->key == key)
diff --git a/output-gazetteer.cpp b/output-gazetteer.cpp
index f556fa4..68e619b 100644
--- a/output-gazetteer.cpp
+++ b/output-gazetteer.cpp
@@ -1,5 +1,4 @@
 #include <libpq-fe.h>
-#include <boost/make_shared.hpp>
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/format.hpp>
 
@@ -12,8 +11,8 @@
 #include "util.hpp"
 
 #include <algorithm>
-
-#define SRID (reproj->project_getprojinfo()->srs)
+#include <iostream>
+#include <memory>
 
 #define CREATE_PLACE_TABLE                      \
    "CREATE TABLE place ("                       \
@@ -43,7 +42,7 @@ enum { BUFFER_SIZE = 4092 };
 void place_tag_processor::clear()
 {
     // set members to sane defaults
-    src = NULL;
+    src = nullptr;
     admin_level = ADMINLEVEL_NONE;
     countrycode = 0;
     housenumber.assign("\\N");
@@ -59,7 +58,7 @@ void place_tag_processor::clear()
 
 struct UnnamedPredicate
 {
-    bool operator()(const tag &val) const {
+    bool operator()(const tag_t &val) const {
         return val.key == "natural" ||
                val.key == "railway" ||
                val.key == "waterway" ||
@@ -83,9 +82,9 @@ void place_tag_processor::process_tags(const taglist_t &tags)
     bool placeadmin = false;
     bool placehouse = false;
     bool placebuilding = false;
-    const tag *place = 0;
-    const tag *junction = 0;
-    const tag *landuse = 0;
+    const tag_t *place = 0;
+    const tag_t *junction = 0;
+    const tag_t *landuse = 0;
     bool isnamed = false;
     bool isinterpolation = false;
     const std::string *house_nr = 0;
@@ -95,224 +94,232 @@ void place_tag_processor::process_tags(const taglist_t &tags)
     clear();
     src = &tags;
 
-    for (taglist_t::const_iterator item = tags.begin(); item != tags.end(); ++item) {
-        if (item->key == "name:prefix") {
-            extratags.push_back(&*item);
-        } else if (item->key == "ref" ||
-                   item->key == "int_ref" ||
-                   item->key == "nat_ref" ||
-                   item->key == "reg_ref" ||
-                   item->key == "loc_ref" ||
-                   item->key == "old_ref" ||
-                   item->key == "iata" ||
-                   item->key == "icao" ||
-                   item->key == "operator" ||
-                   item->key == "pcode" ||
-                   boost::starts_with(item->key, "pcode:")) {
-            names.push_back(&*item);
-        } else if (item->key == "name" ||
-                   boost::starts_with(item->key, "name:") ||
-                   item->key == "int_name" ||
-                   boost::starts_with(item->key, "int_name:") ||
-                   item->key == "nat_name" ||
-                   boost::starts_with(item->key, "nat_name:") ||
-                   item->key == "reg_name" ||
-                   boost::starts_with(item->key, "reg_name:") ||
-                   item->key == "loc_name" ||
-                   boost::starts_with(item->key, "loc_name:") ||
-                   item->key == "old_name" ||
-                   boost::starts_with(item->key, "old_name:") ||
-                   item->key == "alt_name" ||
-                   boost::starts_with(item->key, "alt_name:") ||
-                   boost::starts_with(item->key, "alt_name_") ||
-                   item->key == "official_name" ||
-                   boost::starts_with(item->key, "official_name:") ||
-                   item->key == "place_name" ||
-                   boost::starts_with(item->key, "place_name:") ||
-                   item->key == "short_name" ||
-                   boost::starts_with(item->key, "short_name:") ||
-                   item->key == "brand") {
-            names.push_back(&*item);
+    for (const auto& item: tags) {
+        if (boost::ends_with(item.key, "source")) {
+            // ignore
+        } else if (item.key == "name:prefix" ||
+                   item.key == "name:botanical" ||
+                   boost::ends_with(item.key, "wikidata")) {
+            extratags.push_back(&item);
+        } else if (item.key == "ref" ||
+                   item.key == "int_ref" ||
+                   item.key == "nat_ref" ||
+                   item.key == "reg_ref" ||
+                   item.key == "loc_ref" ||
+                   item.key == "old_ref" ||
+                   item.key == "iata" ||
+                   item.key == "icao" ||
+                   item.key == "operator" ||
+                   item.key == "pcode" ||
+                   boost::starts_with(item.key, "pcode:")) {
+            names.push_back(&item);
+        } else if (item.key == "name" ||
+                   boost::starts_with(item.key, "name:") ||
+                   item.key == "int_name" ||
+                   boost::starts_with(item.key, "int_name:") ||
+                   item.key == "nat_name" ||
+                   boost::starts_with(item.key, "nat_name:") ||
+                   item.key == "reg_name" ||
+                   boost::starts_with(item.key, "reg_name:") ||
+                   item.key == "loc_name" ||
+                   boost::starts_with(item.key, "loc_name:") ||
+                   item.key == "old_name" ||
+                   boost::starts_with(item.key, "old_name:") ||
+                   item.key == "alt_name" ||
+                   boost::starts_with(item.key, "alt_name:") ||
+                   boost::starts_with(item.key, "alt_name_") ||
+                   item.key == "official_name" ||
+                   boost::starts_with(item.key, "official_name:") ||
+                   item.key == "place_name" ||
+                   boost::starts_with(item.key, "place_name:") ||
+                   item.key == "short_name" ||
+                   boost::starts_with(item.key, "short_name:") ||
+                   item.key == "brand") {
+            names.push_back(&item);
             isnamed = true;
-        } else if (item->key == "addr:housename") {
-            names.push_back(&*item);
+        } else if (item.key == "addr:housename") {
+            names.push_back(&item);
             placehouse = true;
-        } else if (item->key == "emergency") {
-            if (item->value != "fire_hydrant" &&
-                item->value != "yes" &&
-                item->value != "no")
-                places.push_back(*item);
-        } else if (item->key == "tourism" ||
-                   item->key == "historic" ||
-                   item->key == "military") {
-            if (item->value != "no" && item->value != "yes")
-                places.push_back(*item);
-        } else if (item->key == "natural") {
-            if (item->value != "no" &&
-                item->value != "yes" &&
-                item->value != "coastline")
-                places.push_back(*item);
-        } else if (item->key == "landuse") {
-            if (item->value == "cemetry")
-                places.push_back(*item);
+        } else if (item.key == "emergency") {
+            if (item.value != "fire_hydrant" &&
+                item.value != "yes" &&
+                item.value != "no")
+                places.push_back(item);
+        } else if (item.key == "tourism" ||
+                   item.key == "historic" ||
+                   item.key == "military") {
+            if (item.value != "no" && item.value != "yes")
+                places.push_back(item);
+        } else if (item.key == "natural") {
+            if (item.value != "no" &&
+                item.value != "yes" &&
+                item.value != "coastline")
+                places.push_back(item);
+        } else if (item.key == "landuse") {
+            if (item.value == "cemetry")
+                places.push_back(item);
             else
-                landuse = &*item;
-        } else if (item->key == "highway") {
-            if (item->value != "no" &&
-                item->value != "turning_circle" &&
-                item->value != "mini_roundabout" &&
-                item->value != "noexit" &&
-                item->value != "crossing")
-                places.push_back(*item);
-        } else if (item->key == "railway") {
-            if (item->value != "level_crossing" &&
-                item->value != "no")
-                places.push_back(*item);
-        } else if (item->key == "man_made") {
-            if (item->value != "survey_point" &&
-                item->value != "cutline")
-                places.push_back(*item);
-        } else if (item->key == "aerialway") {
-            if (item->value != "pylon" &&
-                item->value != "no")
-                places.push_back(*item);
-        } else if (item->key == "boundary") {
-            if (item->value == "administrative")
+                landuse = &item;
+        } else if (item.key == "highway") {
+            if (item.value == "footway") {
+                auto *footway = tags.get("footway");
+                if (footway == nullptr || *footway != "sidewalk")
+                    places.push_back(item);
+            } else if (item.value != "no" &&
+                item.value != "turning_circle" &&
+                item.value != "mini_roundabout" &&
+                item.value != "noexit" &&
+                item.value != "crossing")
+                places.push_back(item);
+        } else if (item.key == "railway") {
+            if (item.value != "level_crossing" &&
+                item.value != "no")
+                places.push_back(item);
+        } else if (item.key == "man_made") {
+            if (item.value != "survey_point" &&
+                item.value != "cutline")
+                places.push_back(item);
+        } else if (item.key == "aerialway") {
+            if (item.value != "pylon" &&
+                item.value != "no")
+                places.push_back(item);
+        } else if (item.key == "boundary") {
+            if (item.value == "administrative")
                 placeadmin = true;
-            places.push_back(*item);
-        } else if (item->key == "aeroway" ||
-                   item->key == "amenity" ||
-                   item->key == "boundary" ||
-                   item->key == "bridge" ||
-                   item->key == "craft" ||
-                   item->key == "leisure" ||
-                   item->key == "office" ||
-                   item->key == "shop" ||
-                   item->key == "tunnel" ||
-                   item->key == "mountain_pass") {
-            if (item->value != "no")
+            places.push_back(item);
+        } else if (item.key == "aeroway" ||
+                   item.key == "amenity" ||
+                   item.key == "boundary" ||
+                   item.key == "bridge" ||
+                   item.key == "craft" ||
+                   item.key == "leisure" ||
+                   item.key == "office" ||
+                   item.key == "shop" ||
+                   item.key == "tunnel" ||
+                   item.key == "mountain_pass") {
+            if (item.value != "no")
             {
-                places.push_back(*item);
+                places.push_back(item);
             }
-        } else if (item->key == "waterway") {
-            if (item->value != "riverbank")
-                places.push_back(*item);
-        } else if (item->key == "place") {
-            place = &*item;
-        } else if (item->key == "junction") {
-            junction = &*item;
-        } else if (item->key == "addr:interpolation") {
+        } else if (item.key == "waterway") {
+            if (item.value != "riverbank")
+                places.push_back(item);
+        } else if (item.key == "place") {
+            place = &item;
+        } else if (item.key == "junction") {
+            junction = &item;
+        } else if (item.key == "addr:interpolation") {
             housenumber.clear();
-            escape(item->value, housenumber);
+            escape(item.value, housenumber);
             isinterpolation = true;
-        } else if (item->key == "addr:housenumber") {
-            house_nr = &item->value;
+        } else if (item.key == "addr:housenumber") {
+            house_nr = &item.value;
             placehouse = true;
-        } else if (item->key == "addr:conscriptionnumber") {
-            conscr_nr = &item->value;
+        } else if (item.key == "addr:conscriptionnumber") {
+            conscr_nr = &item.value;
             placehouse = true;
-        } else if (item->key == "addr:streetnumber") {
-            street_nr = &item->value;
+        } else if (item.key == "addr:streetnumber") {
+            street_nr = &item.value;
             placehouse = true;
-        } else if (item->key == "addr:street") {
-            street = &item->value;
-        } else if (item->key == "addr:place") {
-            addr_place = &item->value;
-        } else if (item->key == "postal_code" ||
-                   item->key == "postcode" ||
-                   item->key == "addr:postcode" ||
-                   item->key == "tiger:zip_left" ||
-                   item->key == "tiger:zip_right") {
+        } else if (item.key == "addr:street") {
+            street = &item.value;
+        } else if (item.key == "addr:place") {
+            addr_place = &item.value;
+        } else if (item.key == "postal_code" ||
+                   item.key == "postcode" ||
+                   item.key == "addr:postcode" ||
+                   item.key == "tiger:zip_left" ||
+                   item.key == "tiger:zip_right") {
             if (!postcode)
-                postcode = &item->value;
-        } else if (item->key == "country_code" ||
-                   item->key == "ISO3166-1" ||
-                   item->key == "is_in:country_code" ||
-                   item->key == "addr:country" ||
-                   item->key == "addr:country_code") {
-            if (item->value.length() == 2)
-                countrycode = &item->value;
-        } else if (boost::starts_with(item->key, "addr:") ||
-                   item->key == "is_in" ||
-                   boost::starts_with(item->key, "is_in:") ||
-                   item->key == "tiger:county") {
-            address.push_back(&*item);
-        } else if (item->key == "admin_level") {
-            admin_level = atoi(item->value.c_str());
+                postcode = &item.value;
+        } else if (item.key == "country_code" ||
+                   item.key == "ISO3166-1" ||
+                   item.key == "is_in:country_code" ||
+                   item.key == "addr:country" ||
+                   item.key == "addr:country_code") {
+            if (item.value.length() == 2)
+                countrycode = &item.value;
+        } else if (boost::starts_with(item.key, "addr:") ||
+                   item.key == "is_in" ||
+                   boost::starts_with(item.key, "is_in:") ||
+                   item.key == "tiger:county") {
+            address.push_back(&item);
+        } else if (item.key == "admin_level") {
+            admin_level = atoi(item.value.c_str());
             if (admin_level <= 0 || admin_level > 100)
                 admin_level = 100;
-        } else if (item->key == "tracktype" ||
-                   item->key == "traffic_calming" ||
-                   item->key == "service" ||
-                   item->key == "cuisine" ||
-                   item->key == "capital" ||
-                   item->key == "dispensing" ||
-                   item->key == "religion" ||
-                   item->key == "denomination" ||
-                   item->key == "sport" ||
-                   item->key == "internet_access" ||
-                   item->key == "lanes" ||
-                   item->key == "surface" ||
-                   item->key == "smoothness" ||
-                   item->key == "width" ||
-                   item->key == "est_width" ||
-                   item->key == "incline" ||
-                   item->key == "opening_hours" ||
-                   item->key == "collection_times" ||
-                   item->key == "service_times" ||
-                   item->key == "disused" ||
-                   item->key == "wheelchair" ||
-                   item->key == "sac_scale" ||
-                   item->key == "trail_visibility" ||
-                   item->key == "mtb:scale" ||
-                   item->key == "mtb:description" ||
-                   item->key == "wood" ||
-                   item->key == "drive_through" ||
-                   item->key == "drive_in" ||
-                   item->key == "access" ||
-                   item->key == "vehicle" ||
-                   item->key == "bicyle" ||
-                   item->key == "foot" ||
-                   item->key == "goods" ||
-                   item->key == "hgv" ||
-                   item->key == "motor_vehicle" ||
-                   item->key == "motor_car" ||
-                   boost::starts_with(item->key, "access:") ||
-                   boost::starts_with(item->key, "contact:") ||
-                   boost::starts_with(item->key, "drink:") ||
-                   item->key == "oneway" ||
-                   item->key == "date_on" ||
-                   item->key == "date_off" ||
-                   item->key == "day_on" ||
-                   item->key == "day_off" ||
-                   item->key == "hour_on" ||
-                   item->key == "hour_off" ||
-                   item->key == "maxweight" ||
-                   item->key == "maxheight" ||
-                   item->key == "maxspeed" ||
-                   item->key == "fee" ||
-                   item->key == "toll" ||
-                   boost::starts_with(item->key, "toll:") ||
-                   item->key == "charge" ||
-                   item->key == "population" ||
-                   item->key == "description" ||
-                   item->key == "image" ||
-                   item->key == "attribution" ||
-                   item->key == "fax" ||
-                   item->key == "email" ||
-                   item->key == "url" ||
-                   item->key == "website" ||
-                   item->key == "phone" ||
-                   item->key == "real_ale" ||
-                   item->key == "smoking" ||
-                   item->key == "food" ||
-                   item->key == "camera" ||
-                   item->key == "brewery" ||
-                   item->key == "locality" ||
-                   item->key == "wikipedia" ||
-                   boost::starts_with(item->key, "wikipedia:")) {
-            extratags.push_back(&*item);
-        } else if (item->key == "building") {
+        } else if (item.key == "tracktype" ||
+                   item.key == "traffic_calming" ||
+                   item.key == "service" ||
+                   item.key == "cuisine" ||
+                   item.key == "capital" ||
+                   item.key == "dispensing" ||
+                   item.key == "religion" ||
+                   item.key == "denomination" ||
+                   item.key == "sport" ||
+                   item.key == "internet_access" ||
+                   item.key == "lanes" ||
+                   item.key == "surface" ||
+                   item.key == "smoothness" ||
+                   item.key == "width" ||
+                   item.key == "est_width" ||
+                   item.key == "incline" ||
+                   item.key == "opening_hours" ||
+                   item.key == "collection_times" ||
+                   item.key == "service_times" ||
+                   item.key == "disused" ||
+                   item.key == "wheelchair" ||
+                   item.key == "sac_scale" ||
+                   item.key == "trail_visibility" ||
+                   item.key == "mtb:scale" ||
+                   item.key == "mtb:description" ||
+                   item.key == "wood" ||
+                   item.key == "drive_through" ||
+                   item.key == "drive_in" ||
+                   item.key == "access" ||
+                   item.key == "vehicle" ||
+                   item.key == "bicyle" ||
+                   item.key == "foot" ||
+                   item.key == "goods" ||
+                   item.key == "hgv" ||
+                   item.key == "motor_vehicle" ||
+                   item.key == "motor_car" ||
+                   boost::starts_with(item.key, "access:") ||
+                   boost::starts_with(item.key, "contact:") ||
+                   boost::starts_with(item.key, "drink:") ||
+                   item.key == "oneway" ||
+                   item.key == "date_on" ||
+                   item.key == "date_off" ||
+                   item.key == "day_on" ||
+                   item.key == "day_off" ||
+                   item.key == "hour_on" ||
+                   item.key == "hour_off" ||
+                   item.key == "maxweight" ||
+                   item.key == "maxheight" ||
+                   item.key == "maxspeed" ||
+                   item.key == "fee" ||
+                   item.key == "toll" ||
+                   boost::starts_with(item.key, "toll:") ||
+                   item.key == "charge" ||
+                   item.key == "population" ||
+                   item.key == "description" ||
+                   item.key == "image" ||
+                   item.key == "attribution" ||
+                   item.key == "fax" ||
+                   item.key == "email" ||
+                   item.key == "url" ||
+                   item.key == "website" ||
+                   item.key == "phone" ||
+                   item.key == "real_ale" ||
+                   item.key == "smoking" ||
+                   item.key == "food" ||
+                   item.key == "camera" ||
+                   item.key == "brewery" ||
+                   item.key == "locality" ||
+                   item.key == "wikipedia" ||
+                   boost::starts_with(item.key, "wikipedia:")) {
+            extratags.push_back(&item);
+        } else if (item.key == "building") {
             placebuilding = true;
         }
     }
@@ -326,7 +333,7 @@ void place_tag_processor::process_tags(const taglist_t &tags)
     }
 
     if (isinterpolation)
-        places.push_back(tag("place", "houses"));
+        places.push_back(tag_t("place", "houses"));
 
     if (place) {
         if (isinterpolation ||
@@ -347,11 +354,11 @@ void place_tag_processor::process_tags(const taglist_t &tags)
 
     if (places.empty()) {
         if (placebuilding && (!names.empty() || placehouse || postcode)) {
-            places.push_back(tag("building", "yes"));
+            places.push_back(tag_t("building", "yes"));
         } else if (placehouse) {
-            places.push_back(tag("place", "house"));
+            places.push_back(tag_t("place", "house"));
         } else if (postcode) {
-            places.push_back(tag("place", "postcode"));
+            places.push_back(tag_t("place", "postcode"));
         }
     }
 
@@ -377,10 +384,10 @@ void place_tag_processor::process_tags(const taglist_t &tags)
 }
 
 void place_tag_processor::copy_out(char osm_type, osmid_t osm_id,
-                                   const std::string &wkt,
+                                   const std::string &geom,
                                    std::string &buffer)
 {
-    BOOST_FOREACH(const tag &place, places) {
+    for (const auto& place: places) {
         std::string name;
         if (place.key == "bridge" || place.key == "tunnel") {
             name = domain_name(place.key);
@@ -410,7 +417,7 @@ void place_tag_processor::copy_out(char osm_type, osmid_t osm_id,
             bool shop = (place.key == "shop") ||
                         (place.key == "amenity") ||
                         (place.key == "tourism");
-            BOOST_FOREACH(const tag *entry, names) {
+            for (const auto entry: names) {
                 if (!shop && (entry->key == "operator"))
                     continue;
 
@@ -439,7 +446,7 @@ void place_tag_processor::copy_out(char osm_type, osmid_t osm_id,
         copy_opt_string(addr_place, buffer);
         // isin
         if (!address.empty()) {
-            BOOST_FOREACH(const tag *entry, address) {
+            for (const auto entry: address) {
                 if (entry->key == "tiger:county") {
                     escape(std::string(entry->value, 0, entry->value.find(",")),
                            buffer);
@@ -461,7 +468,7 @@ void place_tag_processor::copy_out(char osm_type, osmid_t osm_id,
             buffer += "\\N\t";
         } else {
             bool first = true;
-            BOOST_FOREACH(const tag *entry, extratags) {
+            for (const auto entry: extratags) {
                 if (first)
                     first = false;
                 else
@@ -475,9 +482,9 @@ void place_tag_processor::copy_out(char osm_type, osmid_t osm_id,
             }
             buffer += "\t";
         }
-        // wkt
+        // geometry
         buffer += srid_str;
-        buffer += wkt;
+        buffer += geom;
         buffer += '\n';
     }
 }
@@ -495,7 +502,7 @@ void output_gazetteer_t::stop_copy(void)
     }
 
     /* Terminate the copy */
-    if (PQputCopyEnd(Connection, NULL) != 1)
+    if (PQputCopyEnd(Connection, nullptr) != 1)
     {
         std::cerr << "COPY_END for place failed: " << PQerrorMessage(Connection) << "\n";
         util::exit_nicely();
@@ -576,7 +583,7 @@ void output_gazetteer_t::delete_place(char osm_type, osmid_t osm_id)
 
 int output_gazetteer_t::connect() {
     /* Connection to the database */
-    Connection = PQconnectdb(m_options.conninfo.c_str());
+    Connection = PQconnectdb(m_options.database_options.conninfo().c_str());
 
     /* Check to see that the backend connection was successfully made */
     if (PQstatus(Connection) != CONNECTION_OK) {
@@ -585,7 +592,7 @@ int output_gazetteer_t::connect() {
     }
 
     if (m_options.append) {
-        ConnectionDelete = PQconnectdb(m_options.conninfo.c_str());
+        ConnectionDelete = PQconnectdb(m_options.database_options.conninfo().c_str());
         if (PQstatus(ConnectionDelete) != CONNECTION_OK)
         {
             std::cerr << "Connection to database failed: " << PQerrorMessage(Connection) << "\n";
@@ -599,10 +606,10 @@ int output_gazetteer_t::connect() {
 
 int output_gazetteer_t::start()
 {
-   reproj = m_options.projection;
+   int srid = m_options.projection->target_srs();
    builder.set_exclude_broken_polygon(m_options.excludepoly);
 
-   places.srid_str = (boost::format("SRID=%1%;") % SRID).str();
+   places.srid_str = (boost::format("SRID=%1%;") % srid).str();
 
    if(connect())
        util::exit_nicely();
@@ -629,7 +636,7 @@ int output_gazetteer_t::start()
           pgsql_exec(Connection, PGRES_COMMAND_OK, CREATE_PLACE_ID_INDEX, "", "");
       }
 
-      pgsql_exec(Connection, PGRES_TUPLES_OK, "SELECT AddGeometryColumn('place', 'geometry', %d, 'GEOMETRY', 2)", SRID);
+      pgsql_exec(Connection, PGRES_TUPLES_OK, "SELECT AddGeometryColumn('place', 'geometry', %d, 'GEOMETRY', 2)", srid);
       pgsql_exec(Connection, PGRES_COMMAND_OK, "ALTER TABLE place ALTER COLUMN geometry SET NOT NULL");
    }
 
@@ -687,9 +694,9 @@ int output_gazetteer_t::process_way(osmid_t id, const idlist_t &nds, const tagli
         m_mid->nodes_get_list(nodes, nds);
 
         /* Get the geometry of the object */
-        geometry_builder::maybe_wkt_t wkt = builder.get_wkt_simple(nodes, 1);
-        if (wkt) {
-            places.copy_out('W', id, wkt->geom, buffer);
+        auto geom = builder.get_wkb_simple(nodes, 1);
+        if (geom.valid()) {
+            places.copy_out('W', id, geom.geom, buffer);
             flush_place_buffer();
         }
     }
@@ -725,10 +732,10 @@ int output_gazetteer_t::process_relation(osmid_t id, const memberlist_t &members
 
     /* get the boundary path (ways) */
     idlist_t xid2;
-    for (memberlist_t::const_iterator it = members.begin(); it != members.end(); ++it) {
+    for (const auto& member: members) {
         /* only interested in ways */
-        if (it->type == OSMTYPE_WAY)
-            xid2.push_back(it->id);
+        if (member.type == OSMTYPE_WAY)
+            xid2.push_back(member.id);
     }
 
     if (xid2.empty()) {
@@ -744,11 +751,10 @@ int output_gazetteer_t::process_relation(osmid_t id, const memberlist_t &members
     m_mid->ways_get_list(xid2, xid, xtags, xnodes);
 
     if (cmp_waterway) {
-        geometry_builder::maybe_wkts_t wkts = builder.build_both(xnodes, 1, 1, 1000000, id);
-        for (geometry_builder::wkt_itr wkt = wkts->begin(); wkt != wkts->end(); ++wkt) {
-            if (boost::starts_with(wkt->geom,  "POLYGON")
-                    || boost::starts_with(wkt->geom,  "MULTIPOLYGON")) {
-                places.copy_out('R', id, wkt->geom, buffer);
+        auto geoms = builder.build_both(xnodes, 1, 1, 1000000, id);
+        for (const auto& geom: geoms) {
+            if (geom.is_polygon()) {
+                places.copy_out('R', id, geom.geom, buffer);
                 flush_place_buffer();
             } else {
                 /* add_polygon_error('R', id, "boundary", "adminitrative", &names, countrycode, wkt); */
@@ -756,9 +762,9 @@ int output_gazetteer_t::process_relation(osmid_t id, const memberlist_t &members
         }
     } else {
         /* waterways result in multilinestrings */
-        geometry_builder::maybe_wkt_t wkt = builder.build_multilines(xnodes, id);
-        if ((wkt->geom).length() > 0) {
-            places.copy_out('R', id, wkt->geom, buffer);
+        auto geom = builder.build_multilines(xnodes, id);
+        if (geom.valid()) {
+            places.copy_out('R', id, geom.geom, buffer);
             flush_place_buffer();
         }
     }
diff --git a/output-gazetteer.hpp b/output-gazetteer.hpp
index 95cd318..234ea3f 100644
--- a/output-gazetteer.hpp
+++ b/output-gazetteer.hpp
@@ -1,20 +1,18 @@
 #ifndef OUTPUT_GAZETTEER_H
 #define OUTPUT_GAZETTEER_H
 
+#include <memory>
+#include <string>
+
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/format.hpp>
+
+#include "geometry-builder.hpp"
 #include "osmtypes.hpp"
 #include "output.hpp"
-#include "geometry-builder.hpp"
 #include "pgsql.hpp"
 #include "util.hpp"
 
-#include <boost/shared_ptr.hpp>
-#include <boost/foreach.hpp>
-#include <boost/format.hpp>
-#include <boost/algorithm/string/predicate.hpp>
-
-#include <string>
-#include <iostream>
-
 /**
  * A private class to convert tags.
  */
@@ -37,7 +35,7 @@ public:
 
     bool has_place(const std::string &cls)
     {
-        BOOST_FOREACH(const tag &item, places) {
+        for (const auto& item: places) {
             if (cls == item.key)
                 return true;
         }
@@ -45,7 +43,7 @@ public:
         return false;
     }
 
-    void copy_out(char osm_type, osmid_t osm_id, const std::string &wkt,
+    void copy_out(char osm_type, osmid_t osm_id, const std::string &geom,
                   std::string &buffer);
 
     void clear();
@@ -68,19 +66,19 @@ private:
 
         std::string prefix(cls + ":name");
 
-        for (taglist_t::const_iterator item = src->begin(); item != src->end(); ++item) {
-            if (boost::starts_with(item->key, prefix) &&
-                (item->key.length() == prefix.length()
-                 || item->key[prefix.length()] == ':')) {
+        for (const auto& item: *src) {
+            if (boost::starts_with(item.key, prefix) &&
+                (item.key.length() == prefix.length()
+                 || item.key[prefix.length()] == ':')) {
                 if (!hasname) {
-                    ret.reserve(item->key.length() + item->value.length() + 10);
+                    ret.reserve(item.key.length() + item.value.length() + 10);
                     hasname = true;
                 } else
                     ret += ",";
                 ret += "\"";
-                escape_array_record(std::string(item->key, cls.length() + 1), ret);
+                escape_array_record(std::string(item.key, cls.length() + 1), ret);
                 ret += "\"=>\"";
-                escape_array_record(item->value, ret);
+                escape_array_record(item.value, ret);
                 ret += "\"";
             }
         }
@@ -91,7 +89,7 @@ private:
 
     void escape_array_record(const std::string &in, std::string &out)
     {
-        BOOST_FOREACH(const char c, in) {
+        for (const char c: in) {
             switch(c) {
                 case '\\': out += "\\\\\\\\\\\\\\\\"; break;
                 case '\n':
@@ -106,10 +104,10 @@ private:
     }
 
 
-    std::vector<tag> places;
-    std::vector<const tag *> names;
-    std::vector<const tag *> extratags;
-    std::vector<const tag *> address;
+    std::vector<tag_t> places;
+    std::vector<const tag_t *> names;
+    std::vector<const tag_t *> extratags;
+    std::vector<const tag_t *> address;
     const taglist_t *src;
     int admin_level;
     const std::string *countrycode;
@@ -155,11 +153,11 @@ public:
 
     virtual ~output_gazetteer_t() {}
 
-    virtual boost::shared_ptr<output_t> clone(const middle_query_t* cloned_middle) const
+    virtual std::shared_ptr<output_t> clone(const middle_query_t* cloned_middle) const
     {
         output_gazetteer_t *clone = new output_gazetteer_t(*this);
         clone->m_mid = cloned_middle;
-        return boost::shared_ptr<output_t>(clone);
+        return std::shared_ptr<output_t>(clone);
     }
 
     int start();
@@ -262,7 +260,7 @@ private:
 
     geometry_builder builder;
 
-    boost::shared_ptr<reprojection> reproj;
+    std::shared_ptr<reprojection> reproj;
 
     // string formatters
     // Need to be part of the class, so we have one per thread.
diff --git a/output-multi.cpp b/output-multi.cpp
index 2e406a1..8e61cc4 100644
--- a/output-multi.cpp
+++ b/output-multi.cpp
@@ -12,7 +12,7 @@
 #include <vector>
 
 output_multi_t::output_multi_t(const std::string &name,
-                               boost::shared_ptr<geometry_processor> processor_,
+                               std::shared_ptr<geometry_processor> processor_,
                                const struct export_list &export_list_,
                                const middle_query_t* mid_, const options_t &options_)
     : output_t(mid_, options_),
@@ -21,7 +21,7 @@ output_multi_t::output_multi_t(const std::string &name,
       m_processor(processor_),
       //TODO: we could in fact have something that is interested in nodes and ways..
       m_osm_type(m_processor->interests(geometry_processor::interest_node) ? OSMTYPE_NODE : OSMTYPE_WAY),
-      m_table(new table_t(m_options.conninfo, name, m_processor->column_type(),
+      m_table(new table_t(m_options.database_options.conninfo(), name, m_processor->column_type(),
                           m_export_list->normal_columns(m_osm_type),
                           m_options.hstore_columns, m_processor->srid(),
                           m_options.append, m_options.slim, m_options.droptemp,
@@ -42,13 +42,13 @@ output_multi_t::output_multi_t(const output_multi_t& other):
 output_multi_t::~output_multi_t() {
 }
 
-boost::shared_ptr<output_t> output_multi_t::clone(const middle_query_t* cloned_middle) const{
+std::shared_ptr<output_t> output_multi_t::clone(const middle_query_t* cloned_middle) const{
     output_multi_t *clone = new output_multi_t(*this);
     clone->m_mid = cloned_middle;
     //NOTE: we need to know which ways were used by relations so each thread
     //must have a copy of the original marked done ways, its read only so its ok
     clone->ways_done_tracker = ways_done_tracker;
-    return boost::shared_ptr<output_t>(clone);
+    return std::shared_ptr<output_t>(clone);
 }
 
 int output_multi_t::start() {
@@ -105,7 +105,7 @@ int output_multi_t::pending_way(osmid_t id, int exists) {
     int ret = 0;
 
     // Try to fetch the way from the DB
-    if (!m_mid->ways_get(id, tags_int, nodes_int)) {
+    if (m_mid->ways_get(id, tags_int, nodes_int)) {
         // Output the way
         ret = reprocess_way(id, nodes_int, tags_int, exists);
     }
@@ -156,7 +156,7 @@ int output_multi_t::pending_relation(osmid_t id, int exists) {
     int ret = 0;
 
     // Try to fetch the relation from the DB
-    if (!m_mid->relations_get(id, members_int, tags_int)) {
+    if (m_mid->relations_get(id, members_int, tags_int)) {
         ret = process_relation(id, members_int, tags_int, exists);
     }
 
@@ -267,10 +267,10 @@ int output_multi_t::process_node(osmid_t id, double lat, double lon, const tagli
     unsigned int filter = m_tagtransform->filter_node_tags(tags, *m_export_list.get(), outtags, true);
     if (!filter) {
         //grab its geom
-        geometry_builder::maybe_wkt_t wkt = m_processor->process_node(lat, lon);
-        if (wkt) {
+        auto geom = m_processor->process_node(lat, lon);
+        if (geom.valid()) {
             m_expire->from_bbox(lon, lat, lon, lat);
-            copy_to_table(id, wkt->geom.c_str(), outtags);
+            copy_node_to_table(id, geom.geom, outtags);
         }
     }
     return 0;
@@ -295,16 +295,9 @@ int output_multi_t::reprocess_way(osmid_t id, const nodelist_t &nodes, const tag
                                                           *m_export_list.get(), outtags, true);
     if (!filter) {
         //grab its geom
-        geometry_builder::maybe_wkt_t wkt = m_processor->process_way(nodes);
-        if (wkt) {
-            //TODO: need to know if we care about polygons or lines for this output
-            //the difference only being that if its a really large bbox for the poly
-            //it downgrades to just invalidating the line/perimeter anyway
-            if(boost::starts_with(wkt->geom, "POLYGON") || boost::starts_with(wkt->geom, "MULTIPOLYGON"))
-                m_expire->from_nodes_poly(nodes, id);
-            else
-                m_expire->from_nodes_line(nodes);
-            copy_to_table(id, wkt->geom.c_str(), outtags);
+        auto geom = m_processor->process_way(nodes);
+        if (geom.valid()) {
+            copy_to_table(id, geom, outtags, polygon);
         }
     }
     return 0;
@@ -321,23 +314,17 @@ int output_multi_t::process_way(osmid_t id, const idlist_t &nodes, const taglist
         if(m_way_helper.set(nodes, m_mid) < 1)
             return 0;
         //grab its geom
-        geometry_builder::maybe_wkt_t wkt = m_processor->process_way(m_way_helper.node_cache);
+        auto geom = m_processor->process_way(m_way_helper.node_cache);
 
-        if (wkt) {
+        if (geom.valid()) {
             //if we are also interested in relations we need to mark
             //this way pending just in case it shows up in one
             if (m_processor->interests(geometry_processor::interest_relation)) {
                 ways_pending_tracker->mark(id);
-            }//we aren't interested in relations so if it comes in on a relation later we wont keep it
-            else {
-                //TODO: need to know if we care about polygons or lines for this output
-                //the difference only being that if its a really large bbox for the poly
-                //it downgrades to just invalidating the line/perimeter anyway
-                if(boost::starts_with(wkt->geom, "POLYGON") || boost::starts_with(wkt->geom, "MULTIPOLYGON"))
-                    m_expire->from_nodes_poly(m_way_helper.node_cache, id);
-                else
-                    m_expire->from_nodes_line(m_way_helper.node_cache);
-                copy_to_table(id, wkt->geom.c_str(), outtags);
+            } else {
+                // We wouldn't be interested in this as a relation, so no need to mark it pending.
+                // TODO: Does this imply anything for non-multipolygon relations?
+                copy_to_table(id, geom, outtags, polygon);
             }
         }
     }
@@ -376,11 +363,11 @@ int output_multi_t::process_relation(osmid_t id, const memberlist_t &members,
         }
 
         //do the members of this relation have anything interesting to us
-        //NOTE: make_polygon is preset here this is to force the tag matching/superseeded stuff
+        //NOTE: make_polygon is preset here this is to force the tag matching/superseded stuff
         //normally this wouldnt work but we tell the tag transform to allow typeless relations
         //this is needed because the type can get stripped off by the rel_tag filter above
         //if the export list did not include the type tag.
-        //TODO: find a less hacky way to do the matching/superseeded and tag copying stuff without
+        //TODO: find a less hacky way to do the matching/superseded and tag copying stuff without
         //all this trickery
         int make_boundary, make_polygon = 1;
         taglist_t outtags;
@@ -390,20 +377,17 @@ int output_multi_t::process_relation(osmid_t id, const memberlist_t &members,
                                                         *m_export_list.get(), outtags, true);
         if (!filter)
         {
-            geometry_builder::maybe_wkts_t wkts = m_processor->process_relation(m_relation_helper.nodes);
-            if (wkts) {
-                for(geometry_builder::wkt_itr wkt = wkts->begin(); wkt != wkts->end(); ++wkt)
-                {
-                    //TODO: we actually have the nodes in the m_relation_helper and could use them
-                    //instead of having to reparse the wkt in the expiry code
-                    m_expire->from_wkt(wkt->geom.c_str(), -id);
-                    //what part of the code relies on relation members getting negative ids?
-                    copy_to_table(-id, wkt->geom.c_str(), outtags);
-                }
+            auto geoms = m_processor->process_relation(m_relation_helper.nodes);
+            for (const auto geom: geoms) {
+                //TODO: we actually have the nodes in the m_relation_helper and could use them
+                //instead of having to reparse the wkb in the expiry code
+                m_expire->from_wkb(geom.geom.c_str(), -id);
+                //what part of the code relies on relation members getting negative ids?
+                copy_to_table(-id, geom, outtags, make_polygon);
             }
 
             //TODO: should this loop be inside the if above just in case?
-            //take a look at each member to see if its superseeded (tags on it matched the tags on the relation)
+            //take a look at each member to see if its superseded (tags on it matched the tags on the relation)
             for(size_t i = 0; i < m_relation_helper.ways.size(); ++i) {
                 //tags matched so we are keeping this one with this relation
                 if (m_relation_helper.superseeded[i]) {
@@ -421,8 +405,38 @@ int output_multi_t::process_relation(osmid_t id, const memberlist_t &members,
     return 0;
 }
 
-void output_multi_t::copy_to_table(osmid_t id, const char *wkt, const taglist_t &tags) {
-    m_table->write_wkt(id, tags, wkt);
+void output_multi_t::copy_node_to_table(osmid_t id, const std::string &geom, taglist_t &tags) {
+    m_table->write_row(id, tags, geom);
+}
+
+/**
+ * Copies a 2d object(line or polygon) to the table, adding a way_area tag if appropriate
+ * \param id OSM ID of the object
+ * \param geom Geometry string of the object
+ * \param tags List of tags. May be modified.
+ * \param polygon Polygon flag returned from the tag transform (polygon=1)
+ *
+ * \pre geom must be valid.
+ */
+void output_multi_t::copy_to_table(const osmid_t id, const geometry_builder::pg_geom_t &geom, taglist_t &tags, int polygon) {
+    if (geom.is_polygon()) {
+        // It's a polygon table (implied by it turning into a poly),
+        // and it got formed into a polygon, so expire as a polygon and write the geom
+        m_expire->from_nodes_poly(m_way_helper.node_cache, id);
+        if (geom.area > 0.0) {
+            char tmp[32];
+            snprintf(tmp, sizeof(tmp), "%g", geom.area);
+            tags.push_override(tag_t("way_area", tmp));
+        }
+        m_table->write_row(id, tags, geom.geom);
+    } else {
+        // Linestring
+        if (!polygon) {
+            // non-polygons are okay
+            m_expire->from_nodes_line(m_way_helper.node_cache);
+            m_table->write_row(id, tags, geom.geom);
+        }
+    }
 }
 
 void output_multi_t::delete_from_output(osmid_t id) {
@@ -430,22 +444,22 @@ void output_multi_t::delete_from_output(osmid_t id) {
         m_table->delete_row(id);
 }
 
-void output_multi_t::merge_pending_relations(boost::shared_ptr<output_t> other) {
-    boost::shared_ptr<id_tracker> tracker = other.get()->get_pending_relations();
+void output_multi_t::merge_pending_relations(std::shared_ptr<output_t> other) {
+    std::shared_ptr<id_tracker> tracker = other.get()->get_pending_relations();
     osmid_t id;
     while(tracker.get() && id_tracker::is_valid((id = tracker->pop_mark()))){
         rels_pending_tracker->mark(id);
     }
 }
 
-void output_multi_t::merge_expire_trees(boost::shared_ptr<output_t> other) {
+void output_multi_t::merge_expire_trees(std::shared_ptr<output_t> other) {
     if(other->get_expire_tree().get())
         m_expire->merge_and_destroy(*other.get()->get_expire_tree());
 }
 
-boost::shared_ptr<id_tracker> output_multi_t::get_pending_relations() {
+std::shared_ptr<id_tracker> output_multi_t::get_pending_relations() {
     return rels_pending_tracker;
 }
-boost::shared_ptr<expire_tiles> output_multi_t::get_expire_tree() {
+std::shared_ptr<expire_tiles> output_multi_t::get_expire_tree() {
     return m_expire;
 }
diff --git a/output-multi.hpp b/output-multi.hpp
index b2f17ec..3877152 100644
--- a/output-multi.hpp
+++ b/output-multi.hpp
@@ -13,8 +13,7 @@
 
 #include <cstddef>
 #include <string>
-#include <boost/scoped_ptr.hpp>
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
 class table_t;
 class tagtransform;
@@ -27,13 +26,13 @@ struct options_t;
 class output_multi_t : public output_t {
 public:
     output_multi_t(const std::string &name,
-                   boost::shared_ptr<geometry_processor> processor_,
+                   std::shared_ptr<geometry_processor> processor_,
                    const export_list &export_list_,
                    const middle_query_t* mid_, const options_t &options_);
     output_multi_t(const output_multi_t& other);
     virtual ~output_multi_t();
 
-    virtual boost::shared_ptr<output_t> clone(const middle_query_t* cloned_middle) const;
+    virtual std::shared_ptr<output_t> clone(const middle_query_t* cloned_middle) const;
 
     int start();
     void stop();
@@ -59,10 +58,10 @@ public:
 
     size_t pending_count() const;
 
-    void merge_pending_relations(boost::shared_ptr<output_t> other);
-    void merge_expire_trees(boost::shared_ptr<output_t> other);
-    virtual boost::shared_ptr<id_tracker> get_pending_relations();
-    virtual boost::shared_ptr<expire_tiles> get_expire_tree();
+    void merge_pending_relations(std::shared_ptr<output_t> other);
+    void merge_expire_trees(std::shared_ptr<output_t> other);
+    virtual std::shared_ptr<id_tracker> get_pending_relations();
+    virtual std::shared_ptr<expire_tiles> get_expire_tree();
 
 protected:
 
@@ -71,15 +70,16 @@ protected:
     int process_way(osmid_t id, const idlist_t &nodes, const taglist_t &tags);
     int reprocess_way(osmid_t id, const nodelist_t &nodes, const taglist_t &tags, bool exists);
     int process_relation(osmid_t id, const memberlist_t &members, const taglist_t &tags, bool exists, bool pending=false);
-    void copy_to_table(osmid_t id, const char *wkt, const taglist_t &tags);
+    void copy_node_to_table(osmid_t id, const std::string &geom, taglist_t &tags);
+    void copy_to_table(const osmid_t id, const geometry_builder::pg_geom_t &geom, taglist_t &tags, int polygon);
 
-    boost::scoped_ptr<tagtransform> m_tagtransform;
-    boost::scoped_ptr<export_list> m_export_list;
-    boost::shared_ptr<geometry_processor> m_processor;
+    std::unique_ptr<tagtransform> m_tagtransform;
+    std::unique_ptr<export_list> m_export_list;
+    std::shared_ptr<geometry_processor> m_processor;
     const OsmType m_osm_type;
-    boost::scoped_ptr<table_t> m_table;
-    boost::shared_ptr<id_tracker> ways_pending_tracker, ways_done_tracker, rels_pending_tracker;
-    boost::shared_ptr<expire_tiles> m_expire;
+    std::unique_ptr<table_t> m_table;
+    std::shared_ptr<id_tracker> ways_pending_tracker, ways_done_tracker, rels_pending_tracker;
+    std::shared_ptr<expire_tiles> m_expire;
     way_helper m_way_helper;
     relation_helper m_relation_helper;
 
diff --git a/output-null.cpp b/output-null.cpp
index 92a1521..f2383a5 100644
--- a/output-null.cpp
+++ b/output-null.cpp
@@ -67,10 +67,10 @@ int output_null_t::relation_modify(osmid_t, const memberlist_t &, const taglist_
   return 0;
 }
 
-boost::shared_ptr<output_t> output_null_t::clone(const middle_query_t* cloned_middle) const {
+std::shared_ptr<output_t> output_null_t::clone(const middle_query_t* cloned_middle) const {
     output_null_t *clone = new output_null_t(*this);
     clone->m_mid = cloned_middle;
-    return boost::shared_ptr<output_t>(clone);
+    return std::shared_ptr<output_t>(clone);
 }
 
 output_null_t::output_null_t(const middle_query_t* mid_, const options_t &options_): output_t(mid_, options_) {
diff --git a/output-null.hpp b/output-null.hpp
index 7b0c8f9..079fbb8 100644
--- a/output-null.hpp
+++ b/output-null.hpp
@@ -12,7 +12,7 @@ public:
     output_null_t(const output_null_t& other);
     virtual ~output_null_t();
 
-    virtual boost::shared_ptr<output_t> clone(const middle_query_t* cloned_middle) const;
+    virtual std::shared_ptr<output_t> clone(const middle_query_t* cloned_middle) const;
 
     int start();
     void stop();
diff --git a/output-pgsql.cpp b/output-pgsql.cpp
index 33cc553..c5388a7 100644
--- a/output-pgsql.cpp
+++ b/output-pgsql.cpp
@@ -6,43 +6,38 @@
  * emit the final geometry-enabled output formats
 */
 
-#include "config.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <time.h>
+#include <future>
+#include <iostream>
+#include <limits>
+#include <memory>
 #include <stdexcept>
+#include <string>
+
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <unistd.h>
 
-#ifdef HAVE_PTHREAD
-#include <pthread.h>
-#endif
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/bind.hpp>
+#include <boost/exception_ptr.hpp>
+#include <boost/format.hpp>
 
+#include "expire-tiles.hpp"
+#include "middle.hpp"
+#include "node-ram-cache.hpp"
+#include "options.hpp"
 #include "osmtypes.hpp"
-#include "reprojection.hpp"
 #include "output-pgsql.hpp"
-#include "options.hpp"
-#include "middle.hpp"
 #include "pgsql.hpp"
-#include "expire-tiles.hpp"
-#include "wildcmp.hpp"
-#include "node-ram-cache.hpp"
+#include "reprojection.hpp"
 #include "taginfo_impl.hpp"
 #include "tagtransform.hpp"
 #include "util.hpp"
-
-#include <boost/bind.hpp>
-#include <boost/format.hpp>
-#include <boost/foreach.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/algorithm/string/predicate.hpp>
-#include <boost/exception_ptr.hpp>
-#include <iostream>
-#include <limits>
-#include <stdexcept>
+#include "wildcmp.hpp"
 
 /* make the diagnostic information work with older versions of
  * boost - the function signature changed at version 1.54.
@@ -53,15 +48,6 @@
 #define BOOST_DIAGNOSTIC_INFO(e) boost::diagnostic_information((e))
 #endif
 
-#define SRID (reproj->project_getprojinfo()->srs)
-
-/* FIXME: Shouldn't malloc this all to begin with but call realloc()
-   as required. The program will most likely segfault if it reads a
-   style file with more styles than this */
-#define MAX_STYLES 1000
-
-#define NUM_TABLES (output_pgsql_t::t_MAX)
-
 /* example from: pg_dump -F p -t planet_osm gis
 COPY planet_osm (osm_id, name, place, landuse, leisure, "natural", man_made, waterway, highway, railway, amenity, tourism, learning, building, bridge, layer, way) FROM stdin;
 17959841        \N      \N      \N      \N      \N      \N      \N      bus_stop        \N      \N      \N      \N      \N      \N    -\N      0101000020E610000030CCA462B6C3D4BF92998C9B38E04940
@@ -96,55 +82,33 @@ E4C1421D5BF24D06053E7DF4940
 212696  Oswald Road     \N      \N      \N      \N      \N      \N      minor   \N      \N      \N      \N      \N      \N      \N    0102000020E610000004000000467D923B6C22D5BFA359D93EE4DF4940B3976DA7AD11D5BF84BBB376DBDF4940997FF44D9A06D5BF4223D8B8FEDF49404D158C4AEA04D
 5BF5BB39597FCDF4940
 */
-int output_pgsql_t::pgsql_out_way(osmid_t id, const taglist_t &tags, const nodelist_t &nodes, int exists)
+int output_pgsql_t::pgsql_out_way(osmid_t id, taglist_t &outtags,
+                                  const nodelist_t &nodes,
+                                  int polygon, int roads)
 {
-    int polygon = 0, roads = 0;
+     /* Split long ways after around 1 degree or 100km */
     double split_at;
-
-    /* If the flag says this object may exist already, delete it first */
-    if (exists) {
-        pgsql_delete_way_from_output(id);
-        // TODO: this now only has an effect when called from the iterate_ways
-        // call-back, so we need some alternative way to trigger this within
-        // osmdata_t.
-        const idlist_t rel_ids = m_mid->relations_using_way(id);
-        for (idlist_t::const_iterator itr = rel_ids.begin();
-             itr != rel_ids.end(); ++itr) {
-            rels_pending_tracker->mark(*itr);
-        }
-    }
-
-    taglist_t outtags;
-    if (m_tagtransform->filter_way_tags(tags, &polygon, &roads, *m_export_list.get(),
-                                        outtags))
-        return 0;
-    /* Split long ways after around 1 degree or 100km */
-    if (m_options.projection->get_proj_id() == PROJ_LATLONG)
+    if (m_options.projection->target_latlon())
         split_at = 1;
     else
         split_at = 100 * 1000;
 
-    tag *areatag = 0;
-    geometry_builder::maybe_wkts_t wkts = builder.get_wkt_split(nodes, polygon, split_at);
-    for(geometry_builder::wkt_itr wkt = wkts->begin(); wkt != wkts->end(); ++wkt) {
+    char tmp[32];
+    auto wkbs = builder.get_wkb_split(nodes, polygon, split_at);
+    for (const auto& wkb: wkbs) {
         /* FIXME: there should be a better way to detect polygons */
-        if (boost::starts_with(wkt->geom, "POLYGON") || boost::starts_with(wkt->geom, "MULTIPOLYGON")) {
+        if (wkb.is_polygon()) {
             expire->from_nodes_poly(nodes, id);
-            if ((wkt->area > 0.0) && m_enable_way_area) {
-                char tmp[32];
-                snprintf(tmp, sizeof(tmp), "%g", wkt->area);
-                if (!areatag) {
-                    outtags.push_dedupe(tag("way_area", tmp));
-                    areatag = outtags.find("way_area");
-                } else
-                    areatag->value = tmp;
+            if ((wkb.area > 0.0) && m_enable_way_area) {
+                snprintf(tmp, sizeof(tmp), "%g", wkb.area);
+                outtags.push_override(tag_t("way_area", tmp));
             }
-            m_tables[t_poly]->write_wkt(id, outtags, wkt->geom.c_str());
+            m_tables[t_poly]->write_row(id, outtags, wkb.geom);
         } else {
             expire->from_nodes_line(nodes);
-            m_tables[t_line]->write_wkt(id, outtags, wkt->geom.c_str());
+            m_tables[t_line]->write_row(id, outtags, wkb.geom);
             if (roads)
-                m_tables[t_roads]->write_wkt(id, outtags, wkt->geom.c_str());
+                m_tables[t_roads]->write_row(id, outtags, wkb.geom);
         }
     }
 
@@ -168,46 +132,40 @@ int output_pgsql_t::pgsql_out_relation(osmid_t id, const taglist_t &rel_tags,
     taglist_t outtags;
 
     //if its a route relation make_boundary and make_polygon will be false otherwise one or the other will be true
-    if (m_tagtransform->filter_rel_member_tags(rel_tags, xtags, xrole, 
+    if (m_tagtransform->filter_rel_member_tags(rel_tags, xtags, xrole,
               &(members_superseeded[0]), &make_boundary, &make_polygon, &roads,
               *m_export_list.get(), outtags)) {
         return 0;
     }
 
     /* Split long linear ways after around 1 degree or 100km (polygons not effected) */
-    if (m_options.projection->get_proj_id() == PROJ_LATLONG)
+    if (m_options.projection->target_latlon())
         split_at = 1;
     else
         split_at = 100 * 1000;
 
     //this will either make lines or polygons (unless the lines arent a ring or are less than 3 pts) depending on the tag transform above
     //TODO: pick one or the other based on which we expect to care about
-    geometry_builder::maybe_wkts_t wkts  = builder.build_both(xnodes, make_polygon, m_options.enable_multi, split_at, id);
+    auto wkbs  = builder.build_both(xnodes, make_polygon, m_options.enable_multi, split_at, id);
 
-    if (!wkts->size()) {
+    if (wkbs.empty()) {
         return 0;
     }
 
-    tag *areatag = 0;
-    for(geometry_builder::wkt_itr wkt = wkts->begin(); wkt != wkts->end(); ++wkt)
-    {
-        expire->from_wkt(wkt->geom.c_str(), -id);
+    char tmp[32];
+    for (const auto& wkb: wkbs) {
+        expire->from_wkb(wkb.geom.c_str(), -id);
         /* FIXME: there should be a better way to detect polygons */
-        if (boost::starts_with(wkt->geom, "POLYGON") || boost::starts_with(wkt->geom, "MULTIPOLYGON")) {
-            if ((wkt->area > 0.0) && m_enable_way_area) {
-                char tmp[32];
-                snprintf(tmp, sizeof(tmp), "%g", wkt->area);
-                if (!areatag) {
-                    outtags.push_dedupe(tag("way_area", tmp));
-                    areatag = outtags.find("way_area");
-                } else
-                    areatag->value = tmp;
+        if (wkb.is_polygon()) {
+            if ((wkb.area > 0.0) && m_enable_way_area) {
+                snprintf(tmp, sizeof(tmp), "%g", wkb.area);
+                outtags.push_override(tag_t("way_area", tmp));
             }
-            m_tables[t_poly]->write_wkt(-id, outtags, wkt->geom.c_str());
+            m_tables[t_poly]->write_row(-id, outtags, wkb.geom);
         } else {
-            m_tables[t_line]->write_wkt(-id, outtags, wkt->geom.c_str());
+            m_tables[t_line]->write_row(-id, outtags, wkb.geom);
             if (roads)
-                m_tables[t_roads]->write_wkt(-id, outtags, wkt->geom.c_str());
+                m_tables[t_roads]->write_row(-id, outtags, wkb.geom);
         }
     }
 
@@ -230,21 +188,14 @@ int output_pgsql_t::pgsql_out_relation(osmid_t id, const taglist_t &rel_tags,
     // If we are making a boundary then also try adding any relations which form complete rings
     // The linear variants will have already been processed above
     if (make_boundary) {
-        tag *areatag = 0;
-        wkts = builder.build_polygons(xnodes, m_options.enable_multi, id);
-        for(geometry_builder::wkt_itr wkt = wkts->begin(); wkt != wkts->end(); ++wkt)
-        {
-            expire->from_wkt(wkt->geom.c_str(), -id);
-            if ((wkt->area > 0.0) && m_enable_way_area) {
-                char tmp[32];
-                snprintf(tmp, sizeof(tmp), "%g", wkt->area);
-                if (!areatag) {
-                    outtags.push_dedupe(tag("way_area", tmp));
-                    areatag = outtags.find("way_area");
-                } else
-                    areatag->value = tmp;
+        wkbs = builder.build_polygons(xnodes, m_options.enable_multi, id);
+        for (const auto& wkb: wkbs) {
+            expire->from_wkb(wkb.geom.c_str(), -id);
+            if ((wkb.area > 0.0) && m_enable_way_area) {
+                snprintf(tmp, sizeof(tmp), "%g", wkb.area);
+                outtags.push_override(tag_t("way_area", tmp));
             }
-            m_tables[t_poly]->write_wkt(-id, outtags, wkt->geom.c_str());
+            m_tables[t_poly]->write_row(-id, outtags, wkb.geom);
         }
     }
 
@@ -252,29 +203,6 @@ int output_pgsql_t::pgsql_out_relation(osmid_t id, const taglist_t &rel_tags,
 }
 
 
-
-namespace {
-/* Using pthreads requires us to shoe-horn everything into various void*
- * pointers. Improvement for the future: just use boost::thread. */
-struct pthread_thunk {
-  table_t *ptr;
-  boost::exception_ptr error;
-};
-
-extern "C" void *pthread_output_pgsql_stop_one(void *arg) {
-  pthread_thunk *thunk = static_cast<pthread_thunk *>(arg);
-
-  try {
-    thunk->ptr->stop();
-
-  } catch (...) {
-    thunk->error = boost::current_exception();
-  }
-
-  return NULL;
-}
-} // anonymous namespace
-
 void output_pgsql_t::enqueue_ways(pending_queue_t &job_queue, osmid_t id, size_t output_id, size_t& added) {
     osmid_t const prev = ways_pending_tracker->last_returned();
     if (id_tracker::is_valid(prev) && prev >= id) {
@@ -317,16 +245,31 @@ void output_pgsql_t::enqueue_ways(pending_queue_t &job_queue, osmid_t id, size_t
 int output_pgsql_t::pending_way(osmid_t id, int exists) {
     taglist_t tags_int;
     nodelist_t nodes_int;
-    int ret = 0;
 
     // Try to fetch the way from the DB
-    if (!m_mid->ways_get(id, tags_int, nodes_int)) {
-        // Output the way
-        //ret = reprocess_way(id, nodes_int, count_int, &tags_int, exists);
-        ret = pgsql_out_way(id, tags_int, nodes_int, exists);
+    if (m_mid->ways_get(id, tags_int, nodes_int)) {
+        /* If the flag says this object may exist already, delete it first */
+        if (exists) {
+            pgsql_delete_way_from_output(id);
+            // TODO: this now only has an effect when called from the iterate_ways
+            // call-back, so we need some alternative way to trigger this within
+            // osmdata_t.
+            const idlist_t rel_ids = m_mid->relations_using_way(id);
+            for (auto &mid: rel_ids) {
+                rels_pending_tracker->mark(mid);
+            }
+        }
+
+        taglist_t outtags;
+        int polygon;
+        int roads;
+        if (!m_tagtransform->filter_way_tags(tags_int, &polygon, &roads,
+                                            *m_export_list.get(), outtags)) {
+            return pgsql_out_way(id, outtags, nodes_int, polygon, roads);
+        }
     }
 
-    return ret;
+    return 0;
 }
 
 void output_pgsql_t::enqueue_relations(pending_queue_t &job_queue, osmid_t id, size_t output_id, size_t& added) {
@@ -372,7 +315,7 @@ int output_pgsql_t::pending_relation(osmid_t id, int exists) {
     int ret = 0;
 
     // Try to fetch the relation from the DB
-    if (!m_mid->relations_get(id, members_int, tags_int)) {
+    if (m_mid->relations_get(id, members_int, tags_int)) {
         ret = pgsql_process_relation(id, members_int, tags_int, exists, true);
     }
 
@@ -381,63 +324,33 @@ int output_pgsql_t::pending_relation(osmid_t id, int exists) {
 
 void output_pgsql_t::commit()
 {
-    for (int i=0; i<NUM_TABLES; i++) {
-        m_tables[i]->commit();
+    for (const auto &t : m_tables) {
+        t->commit();
     }
 }
 
 void output_pgsql_t::stop()
 {
-    int i;
-#ifdef HAVE_PTHREAD
-    pthread_t threads[NUM_TABLES];
-#endif
-
-#ifdef HAVE_PTHREAD
     if (m_options.parallel_indexing) {
-      pthread_thunk thunks[NUM_TABLES];
-      for (i=0; i<NUM_TABLES; i++) {
-          thunks[i].ptr = m_tables[i].get();
-          thunks[i].error = boost::exception_ptr();
-      }
+      std::vector<std::future<void>> outs;
+      outs.reserve(m_tables.size());
 
-      for (i=0; i<NUM_TABLES; i++) {
-          int ret = pthread_create(&threads[i], NULL, pthread_output_pgsql_stop_one, &thunks[i]);
-          if (ret) {
-              fprintf(stderr, "pthread_create() returned an error (%d)\n", ret);
-              util::exit_nicely();
-          }
+      for (auto &t : m_tables) {
+          outs.push_back(std::async(std::launch::async, &table_t::stop, t));
       }
 
-      // set a flag if there are any errors - this allows us to collect all the
-      // threads and check them all for errors before shutting down the process.
-      bool thread_had_error = false;
-      for (i=0; i<NUM_TABLES; i++) {
-          int ret = pthread_join(threads[i], NULL);
-          if (ret) {
-              fprintf(stderr, "pthread_join() returned an error (%d)\n", ret);
-              thread_had_error = true;
-          }
-          if (thunks[i].error) {
-            std::string error_message = BOOST_DIAGNOSTIC_INFO(thunks[i].error);
-            fprintf(stderr, "pthread_join() returned exception: %s\n", error_message.c_str());
-            thread_had_error = true;
-          }
+      // XXX If one of the stop functions throws an error, this collects all
+      //     the other threads first before exiting. That might take a very
+      //     long time if large indexes are created.
+      for (auto &f : outs) {
+        f.get();
       }
-      if (thread_had_error) {
-        util::exit_nicely();
-      }
-    } else {
-#endif
 
-    /* No longer need to access middle layer -- release memory */
-    //TODO: just let the destructor do this
-    for (i=0; i<NUM_TABLES; i++)
-        m_tables[i]->stop();
-
-#ifdef HAVE_PTHREAD
+    } else {
+      for (const auto &t : m_tables) {
+        t->stop();
+      }
     }
-#endif
 
     expire->output_and_destroy();
     expire.reset();
@@ -457,7 +370,8 @@ int output_pgsql_t::way_add(osmid_t id, const idlist_t &nds, const taglist_t &ta
   taglist_t outtags;
 
   /* Check whether the way is: (1) Exportable, (2) Maybe a polygon */
-  int filter = m_tagtransform->filter_way_tags(tags, &polygon, &roads, *m_export_list.get(), outtags);
+  auto filter = m_tagtransform->filter_way_tags(tags, &polygon, &roads,
+                                                *m_export_list.get(), outtags);
 
   /* If this isn't a polygon then it can not be part of a multipolygon
      Hence only polygons are "pending" */
@@ -468,7 +382,7 @@ int output_pgsql_t::way_add(osmid_t id, const idlist_t &nds, const taglist_t &ta
     /* Get actual node data and generate output */
     nodelist_t nodes;
     m_mid->nodes_get_list(nodes, nds);
-    pgsql_out_way(id, outtags, nodes, 0);
+    pgsql_out_way(id, outtags, nodes, polygon, roads);
   }
   return 0;
 }
@@ -655,7 +569,7 @@ int output_pgsql_t::relation_modify(osmid_t osm_id, const memberlist_t &members,
 
 int output_pgsql_t::start()
 {
-    for(std::vector<boost::shared_ptr<table_t> >::iterator table = m_tables.begin(); table != m_tables.end(); ++table)
+    for(std::vector<std::shared_ptr<table_t> >::iterator table = m_tables.begin(); table != m_tables.end(); ++table)
     {
         //setup the table in postgres
         table->get()->start();
@@ -664,13 +578,13 @@ int output_pgsql_t::start()
     return 0;
 }
 
-boost::shared_ptr<output_t> output_pgsql_t::clone(const middle_query_t* cloned_middle) const {
+std::shared_ptr<output_t> output_pgsql_t::clone(const middle_query_t* cloned_middle) const {
     output_pgsql_t *clone = new output_pgsql_t(*this);
     clone->m_mid = cloned_middle;
     //NOTE: we need to know which ways were used by relations so each thread
     //must have a copy of the original marked done ways, its read only so its ok
     clone->ways_done_tracker = ways_done_tracker;
-    return boost::shared_ptr<output_t>(clone);
+    return std::shared_ptr<output_t>(clone);
 }
 
 output_pgsql_t::output_pgsql_t(const middle_query_t* mid_, const options_t &options_)
@@ -681,6 +595,7 @@ output_pgsql_t::output_pgsql_t(const middle_query_t* mid_, const options_t &opti
 
     reproj = m_options.projection;
     builder.set_exclude_broken_polygon(m_options.excludepoly);
+    if (m_options.reproject_area) builder.set_reprojection(reproj.get());
 
     m_export_list.reset(new export_list());
 
@@ -698,8 +613,8 @@ output_pgsql_t::output_pgsql_t(const middle_query_t* mid_, const options_t &opti
     expire.reset(new expire_tiles(&m_options));
 
     //for each table
-    m_tables.reserve(NUM_TABLES);
-    for (int i=0; i<NUM_TABLES; i++) {
+    m_tables.reserve(t_MAX);
+    for (int i = 0; i < t_MAX; i++) {
 
         //figure out the columns this table needs
         columns_t columns = m_export_list->normal_columns((i == t_point)?OSMTYPE_NODE:OSMTYPE_WAY);
@@ -733,9 +648,10 @@ output_pgsql_t::output_pgsql_t(const middle_query_t* mid_, const options_t &opti
         //tremble in awe of this massive constructor! seriously we are trying to avoid passing an
         //options object because we want to make use of the table_t in output_mutli_t which could
         //have a different tablespace/hstores/etc per table
-        m_tables.push_back(boost::shared_ptr<table_t>(
+        m_tables.push_back(std::shared_ptr<table_t>(
             new table_t(
-                m_options.conninfo, name, type, columns, m_options.hstore_columns, SRID,
+                m_options.database_options.conninfo(), name, type, columns, m_options.hstore_columns,
+                reproj->target_srs(),
                 m_options.append, m_options.slim, m_options.droptemp, m_options.hstore_mode,
                 m_options.enable_hstore_index, m_options.tblsmain_data, m_options.tblsmain_index
             )
@@ -750,9 +666,10 @@ output_pgsql_t::output_pgsql_t(const output_pgsql_t& other):
     ways_pending_tracker(new id_tracker()), ways_done_tracker(new id_tracker()), rels_pending_tracker(new id_tracker())
 {
     builder.set_exclude_broken_polygon(m_options.excludepoly);
-    for(std::vector<boost::shared_ptr<table_t> >::const_iterator t = other.m_tables.begin(); t != other.m_tables.end(); ++t) {
+    if (m_options.reproject_area) builder.set_reprojection(reproj.get());
+    for(std::vector<std::shared_ptr<table_t> >::const_iterator t = other.m_tables.begin(); t != other.m_tables.end(); ++t) {
         //copy constructor will just connect to the already there table
-        m_tables.push_back(boost::shared_ptr<table_t>(new table_t(**t)));
+        m_tables.push_back(std::shared_ptr<table_t>(new table_t(**t)));
     }
 }
 
@@ -763,21 +680,21 @@ size_t output_pgsql_t::pending_count() const {
     return ways_pending_tracker->size() + rels_pending_tracker->size();
 }
 
-void output_pgsql_t::merge_pending_relations(boost::shared_ptr<output_t> other) {
-    boost::shared_ptr<id_tracker> tracker = other->get_pending_relations();
+void output_pgsql_t::merge_pending_relations(std::shared_ptr<output_t> other) {
+    std::shared_ptr<id_tracker> tracker = other->get_pending_relations();
     osmid_t id;
     while(tracker.get() && id_tracker::is_valid((id = tracker->pop_mark()))){
         rels_pending_tracker->mark(id);
     }
 }
-void output_pgsql_t::merge_expire_trees(boost::shared_ptr<output_t> other) {
+void output_pgsql_t::merge_expire_trees(std::shared_ptr<output_t> other) {
     if(other->get_expire_tree().get())
         expire->merge_and_destroy(*other->get_expire_tree());
 }
 
-boost::shared_ptr<id_tracker> output_pgsql_t::get_pending_relations() {
+std::shared_ptr<id_tracker> output_pgsql_t::get_pending_relations() {
     return rels_pending_tracker;
 }
-boost::shared_ptr<expire_tiles> output_pgsql_t::get_expire_tree() {
+std::shared_ptr<expire_tiles> output_pgsql_t::get_expire_tree() {
     return expire;
 }
diff --git a/output-pgsql.hpp b/output-pgsql.hpp
index 59a3567..27bab25 100644
--- a/output-pgsql.hpp
+++ b/output-pgsql.hpp
@@ -15,7 +15,7 @@
 #include "table.hpp"
 
 #include <vector>
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
 class output_pgsql_t : public output_t {
 public:
@@ -27,7 +27,7 @@ public:
     virtual ~output_pgsql_t();
     output_pgsql_t(const output_pgsql_t& other);
 
-    virtual boost::shared_ptr<output_t> clone(const middle_query_t* cloned_middle) const;
+    virtual std::shared_ptr<output_t> clone(const middle_query_t* cloned_middle) const;
 
     int start();
     void stop();
@@ -53,15 +53,16 @@ public:
 
     size_t pending_count() const;
 
-    void merge_pending_relations(boost::shared_ptr<output_t> other);
-    void merge_expire_trees(boost::shared_ptr<output_t> other);
-    virtual boost::shared_ptr<id_tracker> get_pending_relations();
-    virtual boost::shared_ptr<expire_tiles> get_expire_tree();
+    void merge_pending_relations(std::shared_ptr<output_t> other);
+    void merge_expire_trees(std::shared_ptr<output_t> other);
+    virtual std::shared_ptr<id_tracker> get_pending_relations();
+    virtual std::shared_ptr<expire_tiles> get_expire_tree();
 
 protected:
 
     int pgsql_out_node(osmid_t id, const taglist_t &tags, double node_lat, double node_lon);
-    int pgsql_out_way(osmid_t id, const taglist_t &tags, const nodelist_t &nodes, int exists);
+    int pgsql_out_way(osmid_t id, taglist_t &tags, const nodelist_t &nodes,
+                      int polygons, int roads);
     int pgsql_out_relation(osmid_t id, const taglist_t &rel_tags,
                            const multinodelist_t &xnodes, const multitaglist_t & xtags,
                            const idlist_t &xid, const rolelist_t &xrole,
@@ -70,21 +71,21 @@ protected:
     int pgsql_delete_way_from_output(osmid_t osm_id);
     int pgsql_delete_relation_from_output(osmid_t osm_id);
 
-    boost::scoped_ptr<tagtransform> m_tagtransform;
+    std::unique_ptr<tagtransform> m_tagtransform;
 
     //enable output of a generated way_area tag to either hstore or its own column
     int m_enable_way_area;
 
-    std::vector<boost::shared_ptr<table_t> > m_tables;
+    std::vector<std::shared_ptr<table_t> > m_tables;
 
-    boost::scoped_ptr<export_list> m_export_list;
+    std::unique_ptr<export_list> m_export_list;
 
     geometry_builder builder;
 
-    boost::shared_ptr<reprojection> reproj;
-    boost::shared_ptr<expire_tiles> expire;
+    std::shared_ptr<reprojection> reproj;
+    std::shared_ptr<expire_tiles> expire;
 
-    boost::shared_ptr<id_tracker> ways_pending_tracker, ways_done_tracker, rels_pending_tracker;
+    std::shared_ptr<id_tracker> ways_pending_tracker, ways_done_tracker, rels_pending_tracker;
 
     const static std::string NAME;
 };
diff --git a/output.cpp b/output.cpp
index 3a0e335..b6e18f8 100644
--- a/output.cpp
+++ b/output.cpp
@@ -8,9 +8,7 @@
 #include <string.h>
 #include <stdexcept>
 
-#include <boost/make_shared.hpp>
 #include <boost/format.hpp>
-#include <boost/foreach.hpp>
 #include <boost/functional/hash.hpp>
 #include <boost/property_tree/ptree.hpp>
 #include <boost/property_tree/json_parser.hpp>
@@ -27,7 +25,7 @@ void override_if(T &t, const std::string &key, const pt::ptree &conf) {
     }
 }
 
-boost::shared_ptr<output_t> parse_multi_single(const pt::ptree &conf,
+std::shared_ptr<output_t> parse_multi_single(const pt::ptree &conf,
                              const middle_query_t *mid,
                              const options_t &options) {
     options_t new_opts = options;
@@ -45,20 +43,20 @@ boost::shared_ptr<output_t> parse_multi_single(const pt::ptree &conf,
     new_opts.tblsmain_index = conf.get_optional<std::string>("tablespace-index");
     new_opts.tblsmain_data = conf.get_optional<std::string>("tablespace-data");
     override_if<int>(new_opts.hstore_mode, "enable-hstore", conf);
-    override_if<int>(new_opts.enable_hstore_index, "enable-hstore-index", conf);
+    override_if<bool>(new_opts.enable_hstore_index, "enable-hstore-index", conf);
     override_if<bool>(new_opts.enable_multi, "enable-multi", conf);
-    override_if<int>(new_opts.hstore_match_only, "hstore-match-only", conf);
+    override_if<bool>(new_opts.hstore_match_only, "hstore-match-only", conf);
 
     hstores_t hstore_columns;
     boost::optional<const pt::ptree &> hstores = conf.get_child_optional("hstores");
     if (hstores) {
-        BOOST_FOREACH(const pt::ptree::value_type &val, *hstores) {
+        for (const pt::ptree::value_type &val: *hstores) {
             hstore_columns.push_back(val.second.get_value<std::string>());
         }
     }
     new_opts.hstore_columns = hstore_columns;
 
-    boost::shared_ptr<geometry_processor> processor =
+    std::shared_ptr<geometry_processor> processor =
         geometry_processor::create(proc_type, &new_opts);
 
     // TODO: we're faking this up, but there has to be a better way?
@@ -67,7 +65,7 @@ boost::shared_ptr<output_t> parse_multi_single(const pt::ptree &conf,
 
     export_list columns;
     const pt::ptree &tags = conf.get_child("tags");
-    BOOST_FOREACH(const pt::ptree::value_type &val, tags) {
+    for (const pt::ptree::value_type &val: tags) {
         const pt::ptree &tag = val.second;
         taginfo info;
         info.name = tag.get<std::string>("name");
@@ -80,11 +78,11 @@ boost::shared_ptr<output_t> parse_multi_single(const pt::ptree &conf,
         columns.add(osm_type, info);
     }
 
-    return boost::make_shared<output_multi_t>(name, processor, columns, mid, new_opts);
+    return std::make_shared<output_multi_t>(name, processor, columns, mid, new_opts);
 }
 
-std::vector<boost::shared_ptr<output_t> > parse_multi_config(const middle_query_t *mid, const options_t &options) {
-    std::vector<boost::shared_ptr<output_t> > outputs;
+std::vector<std::shared_ptr<output_t> > parse_multi_config(const middle_query_t *mid, const options_t &options) {
+    std::vector<std::shared_ptr<output_t> > outputs;
 
     if (!options.style.empty()) {
         const std::string file_name(options.style);
@@ -93,7 +91,7 @@ std::vector<boost::shared_ptr<output_t> > parse_multi_config(const middle_query_
             pt::ptree conf;
             pt::read_json(file_name, conf);
 
-            BOOST_FOREACH(const pt::ptree::value_type &val, conf) {
+            for (const pt::ptree::value_type &val: conf) {
                 outputs.push_back(parse_multi_single(val.second, mid, options));
             }
 
@@ -110,17 +108,17 @@ std::vector<boost::shared_ptr<output_t> > parse_multi_config(const middle_query_
 
 } // anonymous namespace
 
-std::vector<boost::shared_ptr<output_t> > output_t::create_outputs(const middle_query_t *mid, const options_t &options) {
-    std::vector<boost::shared_ptr<output_t> > outputs;
+std::vector<std::shared_ptr<output_t> > output_t::create_outputs(const middle_query_t *mid, const options_t &options) {
+    std::vector<std::shared_ptr<output_t> > outputs;
 
     if (options.output_backend == "pgsql") {
-        outputs.push_back(boost::make_shared<output_pgsql_t>(mid, options));
+        outputs.push_back(std::make_shared<output_pgsql_t>(mid, options));
 
     } else if (options.output_backend == "gazetteer") {
-        outputs.push_back(boost::make_shared<output_gazetteer_t>(mid, options));
+        outputs.push_back(std::make_shared<output_gazetteer_t>(mid, options));
 
     } else if (options.output_backend == "null") {
-        outputs.push_back(boost::make_shared<output_null_t>(mid, options));
+        outputs.push_back(std::make_shared<output_null_t>(mid, options));
 
     } else if (options.output_backend == "multi") {
         outputs = parse_multi_config(mid, options);
@@ -148,14 +146,14 @@ const options_t *output_t::get_options()const {
 	return &m_options;
 }
 
-void output_t::merge_pending_relations(boost::shared_ptr<output_t> other) {
+void output_t::merge_pending_relations(std::shared_ptr<output_t> other) {
 }
-void output_t::merge_expire_trees(boost::shared_ptr<output_t> other) {
+void output_t::merge_expire_trees(std::shared_ptr<output_t> other) {
 }
 
-boost::shared_ptr<id_tracker> output_t::get_pending_relations() {
-    return boost::shared_ptr<id_tracker>();
+std::shared_ptr<id_tracker> output_t::get_pending_relations() {
+    return std::shared_ptr<id_tracker>();
 }
-boost::shared_ptr<expire_tiles> output_t::get_expire_tree() {
-    return boost::shared_ptr<expire_tiles>();
+std::shared_ptr<expire_tiles> output_t::get_expire_tree() {
+    return std::shared_ptr<expire_tiles>();
 }
diff --git a/output.hpp b/output.hpp
index bf93f5d..ab89695 100644
--- a/output.hpp
+++ b/output.hpp
@@ -10,15 +10,15 @@
 #ifndef OUTPUT_H
 #define OUTPUT_H
 
-#include "options.hpp"
-#include "middle.hpp"
-#include "id-tracker.hpp"
-#include "expire-tiles.hpp"
+#include <stack>
 
 #include <boost/noncopyable.hpp>
-#include <boost/version.hpp>
-#include <utility>
-#include <stack>
+
+#include "options.hpp"
+
+struct expire_tiles;
+struct id_tracker;
+struct middle_query_t;
 
 struct pending_job_t {
     osmid_t osm_id;
@@ -32,12 +32,12 @@ typedef std::stack<pending_job_t> pending_queue_t;
 
 class output_t : public boost::noncopyable {
 public:
-    static std::vector<boost::shared_ptr<output_t> > create_outputs(const middle_query_t *mid, const options_t &options);
+    static std::vector<std::shared_ptr<output_t> > create_outputs(const middle_query_t *mid, const options_t &options);
 
     output_t(const middle_query_t *mid, const options_t &options_);
     virtual ~output_t();
 
-    virtual boost::shared_ptr<output_t> clone(const middle_query_t* cloned_middle) const = 0;
+    virtual std::shared_ptr<output_t> clone(const middle_query_t* cloned_middle) const = 0;
 
     virtual int start() = 0;
     virtual void stop() = 0;
@@ -65,10 +65,10 @@ public:
 
     const options_t *get_options() const;
 
-    virtual void merge_pending_relations(boost::shared_ptr<output_t> other);
-    virtual void merge_expire_trees(boost::shared_ptr<output_t> other);
-    virtual boost::shared_ptr<id_tracker> get_pending_relations();
-    virtual boost::shared_ptr<expire_tiles> get_expire_tree();
+    virtual void merge_pending_relations(std::shared_ptr<output_t> other);
+    virtual void merge_expire_trees(std::shared_ptr<output_t> other);
+    virtual std::shared_ptr<id_tracker> get_pending_relations();
+    virtual std::shared_ptr<expire_tiles> get_expire_tree();
 
 protected:
 
diff --git a/parse-o5m.cpp b/parse-o5m.cpp
deleted file mode 100644
index 5162469..0000000
--- a/parse-o5m.cpp
+++ /dev/null
@@ -1,962 +0,0 @@
-/*
-#-----------------------------------------------------------------------------
-# osm2pgsql - converts planet.osm file into PostgreSQL
-# compatible output suitable to be rendered by mapnik
-#-----------------------------------------------------------------------------
-# Original Python implementation by Artem Pavlenko
-# Re-implementation by Jon Burgess, Copyright 2006
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# 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 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
-#-----------------------------------------------------------------------------
-*/
-
-/* 2011-07-03 02:30
-   Markus Weber */
-
-// when __cplusplus is defined, we need to define this macro as well
-// to get the print format specifiers in the inttypes.h header.
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-#include <stdint.h>
-#include <cstdlib>
-#include <cstring>
-#include <cstdio>
-#include <unistd.h>
-#include <time.h>
-#include <fcntl.h>
-
-#ifdef _WIN32
-#include <io.h>
-#endif
-
-#include "parse-o5m.hpp"
-#include "osmdata.hpp"
-#include "osmtypes.hpp"
-#include "reprojection.hpp"
-
-#define inline
-
-typedef uint8_t byte;
-typedef unsigned int uint;
-#define isdig(x) isdigit((unsigned char)(x))
-static int loglevel= 0;  /* logging to stderr; */
-/* 0: no logging; 1: small logging; 2: normal logging;
-   3: extended logging; */
-#define DP(f) fprintf(stderr,"- Debug: " #f "\n");
-#define DPv(f,...) fprintf(stderr,"- Debug: " #f "\n",__VA_ARGS__);
-#ifdef _WIN32
-#define NL "\r\n"  /* use CR/LF as new-line sequence */
-  #define off_t off64_t
-  #define lseek lseek64
-#else
-#define NL "\n"  /* use LF as new-line sequence */
-  #define O_BINARY 0
-#endif
-
-#define PERR(f) \
-  fprintf(stderr,"osm2pgsql Error: " f "\n");
-/* print error message */
-#define PERRv(f,...) \
-  fprintf(stderr,"osm2pgsql Error: " f "\n",__VA_ARGS__);
-/* print error message with value(s) */
-#define WARN(f) { static int msgn= 3; if(--msgn>=0) \
-  fprintf(stderr,"osm2pgsql Warning: " f "\n"); }
-/* print a warning message, do it maximal 3 times */
-#define WARNv(f,...) { static int msgn= 3; if(--msgn>=0) \
-  fprintf(stderr,"osm2pgsql Warning: " f "\n",__VA_ARGS__); }
-/* print a warning message with value(s), do it maximal 3 times */
-#define PINFO(f) \
-  fprintf(stderr,"osm2pgsql: " f "\n");
-/* print info message */
-#define ONAME(i) \
-  (i==0? "node": i==1? "way": i==2? "relation": "unknown object")
-
-static inline char *stpcpy0(char *dest, const char *src) {
-    /* redefinition of C99's stpcpy() because it's missing in MinGW,
-       and declaration in Linux seems to be wrong; */
-  while(*src!=0)
-    *dest++= *src++;
-  *dest= 0;
-  return dest;
-}  /* end stpcpy0() */
-
-static inline char* uint32toa(uint32_t v,char* s) {
-    /* convert uint32_t integer into string;
-       v: long integer value to convert;
-       return: s;
-       s[]: digit string; */
-  char* s1,*s2;
-  char c;
-
-  s1= s;
-  if(v==0)
-    *s1++= '0';
-  s2= s1;
-  while(v>0)
-    { *s2++= "0123456789"[v%10]; v/= 10; }
-  *s2--= 0;
-  while(s2>s1)
-    { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
-  return s;
-}  /* end   uint32toa() */
-
-static inline void createtimestamp(uint64_t v,char* sp) {
-    /* write a timestamp in OSM format, e.g.: "2010-09-30T19:23:30Z",
-       into a string;
-       v: value of the timestamp;
-       sp[21]: destination string; */
-  time_t vtime;
-  struct tm tm;
-  int i;
-
-  vtime= v;
-  #ifdef _WIN32
-  memcpy(&tm,gmtime(&vtime),sizeof(tm));
-  #else
-  gmtime_r(&vtime,&tm);
-  #endif
-  i= tm.tm_year+1900;
-  sp+= 3; *sp--= i%10+'0';
-  i/=10; *sp--= i%10+'0';
-  i/=10; *sp--= i%10+'0';
-  i/=10; *sp= i%10+'0';
-  sp+= 4; *sp++= '-';
-  i= tm.tm_mon+1;
-  *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= '-';
-  i= tm.tm_mday;
-  *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= 'T';
-  i= tm.tm_hour;
-  *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= ':';
-  i= tm.tm_min;
-  *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= ':';
-  i= tm.tm_sec%60;
-  *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= 'Z'; *sp= 0;
-}  /* end   createtimestamp() */
-
-
-
-/*------------------------------------------------------------
-  Module pbf_   protobuf conversions module
-  ------------------------------------------------------------
-
-  this module provides procedures for conversions from
-  protobuf formats to regular numbers;
-  as usual, all identifiers of a module have the same prefix,
-  in this case 'pbf'; one underline will follow in case of a
-  global accessible object, two underlines in case of objects
-  which are not meant to be accessed from outside this module;
-  the sections of private and public definitions are separated
-  by a horizontal line: ----
-  many procedures have a parameter 'pp'; here, the address of
-  a buffer pointer is expected; this pointer will be incremented
-  by the number of bytes the converted protobuf element consumes;
-
-  ------------------------------------------------------------ */
-
-static inline uint32_t pbf_uint32(byte** pp) {
-    /* get the value of an unsigned integer;
-       pp: see module header; */
-  byte* p;
-  uint32_t i;
-  uint32_t fac;
-
-  p= *pp;
-  i= *p;
-  if((*p & 0x80)==0) {  /* just one byte */
-    (*pp)++;
-return i;
-    }
-  i&= 0x7f;
-  fac= 0x80;
-  while(*++p & 0x80) {  /* more byte(s) will follow */
-    i+= (*p & 0x7f)*fac;
-    fac<<= 7;
-    }
-  i+= *p++ *fac;
-  *pp= p;
-  return i;
-}  /* end   pbf_uint32() */
-
-static inline int32_t pbf_sint32(byte** pp) {
-    /* get the value of an unsigned integer;
-       pp: see module header; */
-  byte* p;
-  int32_t i;
-  int32_t fac;
-  int sig;
-
-  p= *pp;
-  i= *p;
-  if((*p & 0x80)==0) {  /* just one byte */
-    (*pp)++;
-    if(i & 1)  /* negative */
-return -1-(i>>1);
-    else
-return i>>1;
-    }
-  sig= i & 1;
-  i= (i & 0x7e)>>1;
-  fac= 0x40;
-  while(*++p & 0x80) {  /* more byte(s) will follow */
-    i+= (*p & 0x7f)*fac;
-    fac<<= 7;
-    }
-  i+= *p++ *fac;
-  *pp= p;
-  if(sig)  /* negative */
-return -1-i;
-    else
-return i;
-}  /* end   pbf_sint32() */
-
-static inline uint64_t pbf_uint64(byte** pp) {
-    /* get the value of an unsigned integer;
-       pp: see module header; */
-  byte* p;
-  uint64_t i;
-  uint64_t fac;
-
-  p= *pp;
-  i= *p;
-  if((*p & 0x80)==0) {  /* just one byte */
-    (*pp)++;
-return i;
-    }
-  i&= 0x7f;
-  fac= 0x80;
-  while(*++p & 0x80) {  /* more byte(s) will follow */
-    i+= (*p & 0x7f)*fac;
-    fac<<= 7;
-    }
-  i+= *p++ *fac;
-  *pp= p;
-  return i;
-}  /* end   pbf_uint64() */
-
-static inline int64_t pbf_sint64(byte** pp) {
-    /* get the value of a signed integer;
-       pp: see module header; */
-  byte* p;
-  int64_t i;
-  int64_t fac;
-  int sig;
-
-  p= *pp;
-  i= *p;
-  if((*p & 0x80)==0) {  /* just one byte */
-    (*pp)++;
-    if(i & 1)  /* negative */
-return -1-(i>>1);
-    else
-return i>>1;
-    }
-  sig= i & 1;
-  i= (i & 0x7e)>>1;
-  fac= 0x40;
-  while(*++p & 0x80) {  /* more byte(s) will follow */
-    i+= (*p & 0x7f)*fac;
-    fac<<= 7;
-    }
-  i+= *p++ *fac;
-  *pp= p;
-  if(sig)  /* negative */
-return -1-i;
-    else
-return i;
-}  /* end   pbf_sint64() */
-
-#if 0  /* not used at present */
-static inline void pbf_intjump(byte** pp) {
-    /* jump over a protobuf formatted integer;
-       pp: see module header;
-       we do not care about a possibly existing identifier,
-       therefore as the start address *pp the address of the
-       integer value is expected; */
-  byte* p;
-
-  p= *pp;
-  while(*p & 0x80) p++; p++;
-  *pp= p;
-}  /* end   pbf_intjump() */
-#endif
-
-/*------------------------------------------------------------
-  end   Module pbf_   protobuf conversions module
-  ------------------------------------------------------------ */
-
-
-
-/*------------------------------------------------------------
-  Module read_   OSM file read module
-  ------------------------------------------------------------
-
-  this module provides procedures for buffered reading of
-  standard input;
-  as usual, all identifiers of a module have the same prefix,
-  in this case 'read'; one underline will follow in case of a
-  global accessible object, two underlines in case of objects
-  which are not meant to be accessed from outside this module;
-  the sections of private and public definitions are separated
-  by a horizontal line: ---- */
-
-#define read_PREFETCH ((32+3)*1024*1024)
-/* number of bytes which will be available in the buffer after
-   every call of read_input();
-   (important for reading .pbf files:
-   size must be greater than pb__blockM) */
-#define read__bufM (read_PREFETCH*5)  /* length of the buffer; */
-typedef struct {  /* members may not be accessed from external */
-    int fd;  /* file descriptor */
-    bool eof;  /* we are at the end of input file */
-    byte* bufp;  /* pointer in buf[] */
-    byte* bufe;  /* pointer to the end of valid input in buf[] */
-  int64_t read__counter;
-    /* byte counter to get the read position in input file; */
-  uint64_t bufferstart;
-    /* dummy variable which marks the start of the read buffer
-       concatenated  with this instance of read info structure; */
-   } read_info_t;
-
-/*------------------------------------------------------------*/
-
-static read_info_t* read_infop= NULL;
-/* presently used read info structure, i.e. file handle */
-#define read__buf ((byte*)&read_infop->bufferstart)
-/* start address of the file's input buffer */
-static byte* read_bufp= NULL;  /* may be incremented by external */
-/* up to the number of read_PREFETCH bytes before read_input() is
-   called again; */
-static byte* read_bufe= NULL;  /* may not be changed from external */
-
-static int read_open(const char* filename) {
-    /* open an input file;
-       filename[]: path and name of input file;
-               ==NULL: standard input;
-               return: 0: ok; !=0: error;
-               read_infop: handle of the file;
-               note that you should close every opened file with read_close()
-               before the program ends;
-
-               save status of presently processed input file (if any) */
-    if(read_infop!=NULL) {
-    read_infop->bufp= read_bufp;
-    read_infop->bufp= read_bufe;
-    }
-
-    /* get memory space for file information and input buffer */
-  read_infop= (read_info_t*)malloc(sizeof(read_info_t)+read__bufM);
-  if(read_infop==NULL) {
-    PERRv("could not get %i bytes of memory.",read__bufM)
-return 1;
-    }
-
-  /* initialize read info structure */
-  read_infop->fd= 0;  /* (default) standard input */
-  read_infop->eof= false;  /* we are at the end of input file */
-  read_infop->bufp= read_infop->bufe= read__buf;  /* pointer in buf[] */
-  /* pointer to the end of valid input in buf[] */
-  read_infop->read__counter= 0;
-
-  /* set modul-global variables which are associated with this file */
-  read_bufp= read_infop->bufp;
-  read_bufe= read_infop->bufe;
-
-  /* open the file */
-  if(loglevel>=2)
-    fprintf(stderr,"Read-opening: %s",
-      filename==NULL? "stdin": filename);
-  if(filename==NULL)  /* stdin shall be opened */
-    read_infop->fd= 0;
-  else if(filename!=NULL) {  /* a real file shall be opened */
-    read_infop->fd= open(filename,O_RDONLY|O_BINARY);
-    if(read_infop->fd<0) {
-      if(loglevel>=2)
-        fprintf(stderr," -> failed\n");
-      PERRv("could not open input file: %.80s\n",
-        filename==NULL? "standard input": filename)
-      free(read_infop); read_infop= NULL;
-      read_bufp= read_bufe= NULL;
-return 1;
-      }
-  }  /* end   a real file shall be opened */
-  if(loglevel>=2)
-    fprintf(stderr," -> FD %i\n",read_infop->fd);
-return 0;
-}  /* end   read_open() */
-
-static void read_close() {
-    /* close an opened file;
-       read_infop: handle of the file which is to close; */
-  int fd;
-
-  if(read_infop==NULL)  /* handle not valid; */
-return;
-  fd= read_infop->fd;
-  if(loglevel>=1) {  /* verbose */
-      fprintf(stderr,"osm2pgsql: Number of bytes read: %" PRIu64 "\n",
-      read_infop->read__counter);
-    }
-  if(loglevel>=2) {
-    fprintf(stderr,"Read-closing FD: %i\n",fd);
-    }
-  if(fd>0)  /* not standard input */
-    close(fd);
-  free(read_infop); read_infop= NULL;
-  read_bufp= read_bufe= NULL;
-}  /* end   read_close() */
-
-static inline bool read_input() {
-    /* read data from standard input file, use an internal buffer;
-       make data available at read_bufp;
-       read_open() must have been called before calling this procedure;
-       return: there are no (more) bytes to read;
-       read_bufp: start of next bytes available;
-       may be incremented by the caller, up to read_bufe;
-       read_bufe: end of bytes in buffer;
-       must not be changed by the caller;
-       after having called this procedure, the caller may rely on
-       having available at least read_PREFETCH bytes at address
-       read_bufp - with one exception: if there are not enough bytes
-       left to read from standard input, every byte after the end of
-       the reminding part of the file in the buffer will be set to
-       0x00 - up to read_bufp+read_PREFETCH; */
-  int l,r;
-
-  if(read_bufp+read_PREFETCH>=read_bufe) {  /* read buffer is too low */
-      if(!read_infop->eof) {  /* still bytes in the file */
-          if(read_bufe>read_bufp) {  /* bytes remaining in buffer */
-        memmove(read__buf,read_bufp,read_bufe-read_bufp);
-        /* move remaining bytes to start of buffer */
-        read_bufe= read__buf+(read_bufe-read_bufp);
-        /* protect the remaining bytes at buffer start */
-        }
-          else  /* no remaining bytes in buffer */
-              read_bufe= read__buf;  /* no bytes remaining to protect */
-          /* add read bytes to debug counter */
-      read_bufp= read__buf;
-      do {  /* while buffer has not been filled */
-        l= (read__buf+read__bufM)-read_bufe-4;
-        /* number of bytes to read */
-        r= read(read_infop->fd,read_bufe,l);
-        if(r<=0) {  /* no more bytes in the file */
-          read_infop->eof= true;
-          /* memorize that there we are at end of file */
-          l= (read__buf+read__bufM)-read_bufe;
-          /* reminding space in buffer */
-          if(l>read_PREFETCH) l= read_PREFETCH;
-          memset(read_bufe,0,l);
-          /* set reminding space up to prefetch bytes in buffer to 0 */
-      break;
-          }
-        read_infop->read__counter+= r;
-        read_bufe+= r;  /* set new mark for end of data */
-        read_bufe[0]= 0; read_bufe[1]= 0;  /* set 4 null-terminators */
-        read_bufe[2]= 0; read_bufe[3]= 0;
-      } while(r<l);  /* end   while buffer has not been filled */
-      }  /* end   still bytes to read */
-  }  /* end   read buffer is too low */
-  return read_infop->eof && read_bufp>=read_bufe;
-}  /* end   read__input() */
-
-
-/*------------------------------------------------------------
-  end Module read_   OSM file read module
-  ------------------------------------------------------------ */
-
-
-
-/*------------------------------------------------------------
-  Module str_   string read module
-  ------------------------------------------------------------
-
-  this module provides procedures for conversions from
-  strings which have been stored in data stream objects to
-  c-formatted strings;
-  as usual, all identifiers of a module have the same prefix,
-  in this case 'str'; one underline will follow in case of a
-  global accessible object, two underlines in case of objects
-  which are not meant to be accessed from outside this module;
-  the sections of private and public definitions are separated
-  by a horizontal line: ---- */
-
-#define str__tabM (15000+4000)
-/* +4000 because it might happen that an object has a lot of
-   key/val pairs or refroles which are not stored already; */
-#define str__tabstrM 250  /* must be < row size of str__rab[] */
-typedef struct str__info_struct {
-    /* members of this structure must not be accessed
-       from outside this module; */
-  char tab[str__tabM][256];
-    /* string table; see o5m documentation;
-     row length must be at least str__tabstrM+2;
-     each row contains a double string; each of the two strings
-     is terminated by a zero byte, the logical lengths must not
-     exceed str__tabstrM bytes in total;
-     the first str__tabM lines of this array are used as
-     input buffer for strings; */
-    int tabi;  /* index of last entered element in string table; */
-    int tabn;  /* number of valid strings in string table; */
-    struct str__info_struct* prev;  /* address of previous unit; */
-  } str_info_t;
-str_info_t* str__infop= NULL;
-
-static void str__end() {
-    /* clean-up this module; */
-  str_info_t* p;
-
-  while(str__infop!=NULL) {
-    p= str__infop->prev;
-    free(str__infop);
-    str__infop= p;
-    }
-}  /* end str__end() */
-
-/*------------------------------------------------------------*/
-
-static str_info_t* str_open() {
-    /* open an new string client unit;
-       this will allow us to process multiple o5m input files;
-       return: handle of the new unit;
-       ==NULL: error;
-       you do not need to care about closing the unit(s); */
-    static bool firstrun= true;
-  str_info_t* prev;
-
-  prev= str__infop;
-  str__infop= (str_info_t*)malloc(sizeof(str_info_t));
-  if(str__infop==NULL) {
-    PERR("could not get memory for string buffer.")
-return NULL;
-    }
-  str__infop->tabi= 0;
-  str__infop->tabn= 0;
-  str__infop->prev= prev;
-  if(firstrun) {
-    firstrun= false;
-    atexit(str__end);
-    }
-  return str__infop;
-}  /* end   str_open() */
-
-
-static void inline str_reset() {
-    /* clear string table;
-   must be called before any other procedure of this module
-   and may be called every time the string processing shall
-   be restarted; */
-  str__infop->tabi= str__infop->tabn= 0;
-}  /* end   str_reset() */
-
-static void str_read(byte** pp,char** s1p,char** s2p) {
-    /* read an o5m formatted string (pair), e.g. key/val, from
-       standard input buffer;
-       if got a string reference, resolve it, using an internal
-       string table;
-       no reference is used if the strings are longer than
-       250 characters in total (252 including terminators);
-       pp: address of a buffer pointer;
-       this pointer will be incremented by the number of bytes
-       the converted protobuf element consumes;
-       s2p: ==NULL: read not a string pair but a single string;
-       return:
-       *s1p,*s2p: pointers to the strings which have been read; */
-  char* p;
-  int len1,len2;
-  int ref;
-
-  p= (char*)*pp;
-  if(*p==0) {  /* string (pair) given directly */
-    *s1p= ++p;
-    len1= strlen(p);
-    p+= len1+1;
-    if(s2p==NULL) {  /* single string */
-        /* p= strchr(p,0)+1;   jump over second string (if any) */
-      if(len1<=str__tabstrM) {
-        char* tmpcharp;
-
-        /* single string short enough for string table */
-        tmpcharp= stpcpy0(str__infop->tab[str__infop->tabi],*s1p);
-        tmpcharp[1]= 0;
-        /* add a second terminator, just in case someone will try
-           to read this single string as a string pair later; */
-        if(++str__infop->tabi>=str__tabM) str__infop->tabi= 0;
-        if(str__infop->tabn<str__tabM) str__infop->tabn++;
-      }  /* end   single string short enough for string table */
-    }  /* end   single string */
-    else {  /* string pair */
-      *s2p= p;
-      len2= strlen(p);
-      p+= len2+1;
-      if(len1+len2<=str__tabstrM) {
-          /* string pair short enough for string table */
-        memcpy(str__infop->tab[str__infop->tabi],*s1p,len1+len2+2);
-        if(++str__infop->tabi>=str__tabM) str__infop->tabi= 0;
-        if(str__infop->tabn<str__tabM) str__infop->tabn++;
-      }  /*  end   string pair short enough for string table */
-    }  /* end   string pair */
-    *pp= (byte*)p;
-  }  /* end   string (pair) given directly */
-  else {  /* string (pair) given by reference */
-    ref= pbf_uint32(pp);
-    if(ref>str__infop->tabn) {  /* string reference invalid */
-        WARNv("invalid .o5m string reference: %i->%i",
-              str__infop->tabn,ref);
-        *s1p= strdup("(invalid)");
-        if(s2p!=NULL)  /* caller wants a string pair */
-            *s2p= strdup("(invalid)");
-    }  /* end   string reference invalid */
-    else {  /* string reference valid */
-      ref= str__infop->tabi-ref;
-      if(ref<0) ref+= str__tabM;
-      *s1p= str__infop->tab[ref];
-      if(s2p!=NULL)  /* caller wants a string pair */
-        *s2p= strchr(str__infop->tab[ref],0)+1;
-    }  /* end   string reference valid */
-  }  /* end   string (pair) given by reference */
-}  /* end   str_read() */
-
-/*------------------------------------------------------------
-  end   Module str_   string read module
-  ------------------------------------------------------------ */
-
-parse_o5m_t::parse_o5m_t(const int extra_attributes_, const bool bbox_, const boost::shared_ptr<reprojection>& projection_,
-		const double minlon, const double minlat, const double maxlon, const double maxlat):
-		parse_t(extra_attributes_, bbox_, projection_, minlon, minlat, maxlon, maxlat)
-{
-
-}
-
-parse_o5m_t::~parse_o5m_t()
-{
-
-}
-
-int parse_o5m_t::streamFile(const char *filename, const int sanitize, osmdata_t *osmdata) {
-    /* open and parse an .o5m file; */
-    /* return: ==0: ok; !=0: error; */
-    int otype;  /*  type of currently processed object; */
-  /* 0: node; 1: way; 2: relation; */
-  uint32_t hisver;
-  int64_t histime;
-  uint32_t hisuid;
-  char* hisuser;
-  bool endoffile;
-  int64_t o5id;  /* for o5m delta coding */
-  int32_t o5lon,o5lat;  /* for o5m delta coding */
-  int64_t o5histime;  /* for o5m delta coding */
-  int64_t o5hiscset;  /* for o5m delta coding */
-  int64_t o5rid[3];  /* for o5m delta coding */
-  byte* bufp;  /* pointer in read buffer */
-#define bufsp ((char*)bufp)  /* for signed char */
-  byte* bufe;  /* pointer in read buffer, end of object */
-  byte b;  /* latest byte which has been read */
-  int l;
-  byte* bp;
-
-  /* procedure initializations */
-  str_open();
-  /* call some initialization of string read module */
-  str_reset();
-  o5id= 0;
-  o5lat= o5lon= 0;
-  o5hiscset= 0;
-  o5histime= 0;
-  o5rid[0]= o5rid[1]= o5rid[2]= 0;
-
-  /* open the input file */
-  if(read_open(filename)!=0) {
-    fprintf(stderr,"Unable to open %s\n",filename);
-return 1;
-    }
-  endoffile= false;
-
-  /* determine file type */ {
-      const char* p = NULL;
-
-    read_input();
-    if(*read_bufp!=0xff) {  /* cannot be an .o5m file, nor an .o5c file */
-      PERR("File format neither .o5m nor .o5c")
-return 1;
-      }
-    p= strchr(filename,0)-4;  /* get end of filename */
-    if(memcmp(read_bufp,"\xff\xe0\0x04""o5m2",7)==0)
-      filetype= FILETYPE_OSM;
-    else if(memcmp(read_bufp,"\xff\xe0\0x04""o5c2",7)==0)
-      filetype= FILETYPE_OSMCHANGE;
-    else if(p>=filename && strcmp(p,".o5m")==0)
-      filetype= FILETYPE_OSM;
-    else if(p>=filename && (strcmp(p,".o5c")==0 || strcmp(p,".o5h")==0))
-      filetype= FILETYPE_OSMCHANGE;
-    else {
-      WARN("File type not specified. Assuming .o5m")
-      filetype= FILETYPE_OSM;
-      }
-    if(filetype==FILETYPE_OSM)
-      PINFO("Processing .o5m file (not a change file).")
-    else
-      PINFO("Processing .o5c change file.")
-    }
-
-  /* process the input file */
-  for(;;) {  /* read input file */
-
-      /* get next object */
-    read_input();
-    bufp= read_bufp;
-    b= *bufp;
-
-    /* care about file end */
-    if(read_bufp>=read_bufe)  /* at end of input file; */
-  break;
-
-    if(endoffile) {  /* after logical end of file */
-      fprintf(stderr,"osm2pgsql Warning: unexpected contents "
-        "after logical end of file.\n");
-  break;
-      }
-
-    /* care about header and unknown objects */
-    if(b<0x10 || b>0x12) {  /* not a regular dataset id */
-        if(b>=0xf0) {  /* single byte dataset */
-          if(b==0xff) {  /* file start, resp. o5m reset */
-          str_reset();
-          o5id= 0;
-          o5lat= o5lon= 0;
-          o5hiscset= 0;
-          o5histime= 0;
-          o5rid[0]= o5rid[1]= o5rid[2]= 0;
-          }
-        else if(b==0xfe)
-            endoffile= true;
-        else
-          WARNv("unknown .o5m short dataset id: 0x%02x\n",b)
-        read_bufp++;
-  continue;
-      }  /* end   single byte dataset */
-      else {  /* unknown multibyte dataset */
-        if(b!=0xe0 && b!=0xdc)
-              WARNv("unknown .o5m dataset id: 0x%02x\n",b)
-        read_bufp++;
-        l= pbf_uint32(&read_bufp);  /* jump over this dataset */
-        read_bufp+= l;  /* jump over this dataset */
-  continue;
-      }  /* end   unknown multibyte dataset */
-    }  /* end   not a regular dataset id */
-    otype= b&3;
-
-    /* object initialization */
-    hisver= 0;
-    histime= 0;
-    hisuid= 0;
-    hisuser= NULL;
-
-    nds.clear();
-    members.clear();
-
-    /* read object id */
-    bufp++;
-    l= pbf_uint32(&bufp);
-    read_bufp= bufe= bufp+l;
-    osm_id= o5id+= pbf_sint64(&bufp);
-
-    /* do statistics on object id */
-    switch(otype) {
-    case 0:  /* node */
-      if(osm_id>max_node)
-        max_node= osm_id;
-      if (count_node == 0) {
-        time(&start_node);
-      }
-      count_node++;
-      if(count_node%10000==0) print_status();
-      break;
-    case 1:  /* way */
-      if(osm_id>max_way)
-        max_way= osm_id;
-      if (count_way == 0) {
-        time(&start_way);
-      }
-      count_way++;
-      if(count_way%1000==0) print_status();
-      break;
-    case 2:  /* relation */
-      if(osm_id>max_rel)
-        max_rel= osm_id;
-      if (count_rel == 0) {
-        time(&start_rel);
-      }
-      count_rel++;
-      if(count_rel%10==0) print_status();
-      break;
-    default: ;
-      }
-
-    /* read history */ {
-      char tmpstr[50];
-      char* sp;
-
-      hisver= pbf_uint32(&bufp);
-      uint32toa(hisver,tmpstr);
-      tags.push_back(tag("osm_version",tmpstr));
-      if(hisver!=0) {  /* history information available */
-        histime= o5histime+= pbf_sint64(&bufp);
-        createtimestamp(histime,tmpstr);
-        tags.push_back(tag("osm_timestamp",tmpstr));
-        if(histime!=0) {
-          o5hiscset+= pbf_sint32(&bufp);  /* (not used) */
-          str_read(&bufp,&sp,&hisuser);
-          hisuid= pbf_uint64((byte**)&sp);
-          uint32toa(hisuid,tmpstr);
-          tags.push_back(tag("osm_uid",tmpstr));
-          tags.push_back(tag("osm_user",hisuser));
-          }
-      }  /* end   history information available */
-    }  /* end   read history */
-
-    /* perform action */
-    if(bufp>=bufe) {
-        /* just the id and history, i.e. this is a delete request */
-      action= ACTION_DELETE;
-      switch(otype) {
-      case 0:  /* node */
-        osmdata->node_delete(osm_id);
-        break;
-      case 1:  /* way */
-        osmdata->way_delete(osm_id);
-        break;
-      case 2:  /* relation */
-        osmdata->relation_delete(osm_id);
-        break;
-      default: ;
-        }
-      tags.clear();
-      continue;  /* end processing for this object */
-    }  /* end   delete request */
-    else {  /* not a delete request */
-
-        /* determine action */
-      if(filetype==FILETYPE_OSMCHANGE && hisver>1)
-        action= ACTION_MODIFY;
-      else
-        action= ACTION_CREATE;
-
-      /* read coordinates (for nodes only) */
-      if(otype==0) {  /* node */
-          /* read node body */
-        node_lon= (double)(o5lon+= pbf_sint32(&bufp))/10000000;
-        node_lat= (double)(o5lat+= pbf_sint32(&bufp))/10000000;
-        if(!node_wanted(node_lat,node_lon)) {
-          tags.clear();
-  continue;
-          }
-        proj->reproject(&(node_lat),&(node_lon));
-      }  /* end   node */
-
-      /* read noderefs (for ways only) */
-      if(otype==1) {  /* way */
-        l= pbf_uint32(&bufp);
-        bp= bufp+l;
-        if(bp>bufe) bp= bufe;  /* (format error) */
-        while(bufp<bp) {  /* for all noderefs of this way */
-          o5rid[0]+= pbf_sint64(&bufp);
-          nds.push_back(o5rid[0]);
-        }  /* end   for all noderefs of this way */
-      }  /* end   way */
-
-      /* read refs (for relations only) */
-      else if(otype==2) {  /* relation */
-          int64_t ri;  /* temporary, refid */
-        int rt;  /* temporary, reftype */
-        char* rr;  /* temporary, refrole */
-
-        l= pbf_uint32(&bufp);
-        bp= bufp+l;
-        if(bp>bufe) bp= bufe;  /* (format error) */
-        while(bufp<bp) {  /* for all references of this relation */
-          ri= pbf_sint64(&bufp);
-          str_read(&bufp,&rr,NULL);
-          rt= (*rr++ -'0')%3;
-          OsmType type = OSMTYPE_NODE;
-          switch(rt) {
-          case 0:  /* node */
-            type= OSMTYPE_NODE;
-            break;
-          case 1:  /* way */
-            type= OSMTYPE_WAY;
-            break;
-          case 2:  /* relation */
-            type= OSMTYPE_RELATION;
-            break;
-            }
-          o5rid[rt]+= ri;
-          members.push_back(member(type, o5rid[rt], rr));
-        }  /* end   for all references of this relation */
-      }  /* end   relation */
-
-      /* read node key/val pairs */
-      while(bufp<bufe) {  /* for all tags of this object */
-        char* k,*v,*p;
-
-        str_read(&bufp,&k,&v);
-        p= k;
-        while(*p!=0) {
-          if(*p==' ') *p= '_';
-          /* replace all blanks in key by underlines */
-          p++;
-          }
-        tags.push_back(tag(k,v));
-      }  /* end   for all tags of this object */
-
-      /* write object into database */
-      switch(otype) {
-      case 0:  /* node */
-        if(action==ACTION_CREATE)
-          osmdata->node_add(osm_id,
-            node_lat,node_lon,tags);
-        else /* ACTION_MODIFY */
-          osmdata->node_modify(osm_id,
-            node_lat,node_lon,tags);
-        break;
-      case 1:  /* way */
-        if(action==ACTION_CREATE)
-          osmdata->way_add(osm_id,
-            nds,tags);
-        else /* ACTION_MODIFY */
-          osmdata->way_modify(osm_id,
-            nds,tags);
-        break;
-      case 2:  /* relation */
-        if(action==ACTION_CREATE)
-          osmdata->relation_add(osm_id,
-            members,tags);
-        else /* ACTION_MODIFY */
-          osmdata->relation_modify(osm_id,
-            members,tags);
-        break;
-      default: ;
-        }
-
-      /* reset temporary storage lists */
-      tags.clear();
-
-    }  /* end   not a delete request */
-
-  }  /* end   read input file */
-
-  /* close the input file */
-  print_status();
-  read_close();
-  return 0;
-}  /* streamFileO5m() */
diff --git a/parse-o5m.hpp b/parse-o5m.hpp
deleted file mode 100644
index 31774e5..0000000
--- a/parse-o5m.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-#-----------------------------------------------------------------------------
-# osm2pgsql - converts planet.osm file into PostgreSQL
-# compatible output suitable to be rendered by mapnik
-#-----------------------------------------------------------------------------
-# Original Python implementation by Artem Pavlenko
-# Re-implementation by Jon Burgess, Copyright 2006
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# 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 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
-#-----------------------------------------------------------------------------
-*/
-
-#ifndef PARSE_O5M_H
-#define PARSE_O5M_H
-
-#include "parse.hpp"
-#include <boost/shared_ptr.hpp>
-
-struct reprojection;
-
-class parse_o5m_t: public parse_t
-{
-public:
-	parse_o5m_t(const int extra_attributes_, const bool bbox_, const boost::shared_ptr<reprojection>& projection_,
-				const double minlon, const double minlat, const double maxlon, const double maxlat);
-	virtual ~parse_o5m_t();
-	int streamFile(const char *filename, const int sanitize, osmdata_t *osmdata);
-protected:
-	parse_o5m_t();
-};
-
-#endif
diff --git a/parse-osmium.cpp b/parse-osmium.cpp
new file mode 100644
index 0000000..9486517
--- /dev/null
+++ b/parse-osmium.cpp
@@ -0,0 +1,229 @@
+/*
+#-----------------------------------------------------------------------------
+# osm2pgsql - converts planet.osm file into PostgreSQL
+# compatible output suitable to be rendered by mapnik
+#-----------------------------------------------------------------------------
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#-----------------------------------------------------------------------------
+*/
+
+#include <boost/format.hpp>
+
+#include "parse-osmium.hpp"
+#include "reprojection.hpp"
+#include "osmdata.hpp"
+
+#include <osmium/io/any_input.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/visitor.hpp>
+#include <osmium/osm.hpp>
+
+void parse_stats_t::update(const parse_stats_t &other)
+{
+    node += other.node;
+    way += other.way;
+    rel += other.rel;
+}
+
+
+void parse_stats_t::print_summary() const
+{
+    time_t now = time(nullptr);
+    time_t end_nodes = way.start > 0 ? way.start : now;
+    time_t end_way = rel.start > 0 ? rel.start : now;
+    time_t end_rel = now;
+
+    fprintf(stderr,
+            "Node stats: total(%" PRIdOSMID "), max(%" PRIdOSMID ") in %is\n",
+            node.count, node.max,
+            node.count > 0 ? (int) (end_nodes - node.start) : 0);
+    fprintf(stderr,
+            "Way stats: total(%" PRIdOSMID "), max(%" PRIdOSMID ") in %is\n",
+            way.count, way.max,
+            way.count > 0 ? (int) (end_way - way.start) : 0);
+    fprintf(stderr,
+            "Relation stats: total(%" PRIdOSMID "), max(%" PRIdOSMID ") in %is\n",
+            rel.count, rel.max,
+            rel.count > 0 ? (int) (end_rel - rel.start) : 0);
+}
+
+void parse_stats_t::print_status() const
+{
+    time_t now = time(nullptr);
+    time_t end_nodes = way.start > 0 ? way.start : now;
+    time_t end_way = rel.start > 0 ? rel.start : now;
+    time_t end_rel = now;
+    fprintf(stderr,
+            "\rProcessing: Node(%" PRIdOSMID "k %.1fk/s) Way(%" PRIdOSMID "k %.2fk/s) Relation(%" PRIdOSMID " %.2f/s)",
+            node.count / 1000,
+            (double) node.count / 1000.0 / ((int) (end_nodes - node.start) > 0 ? (double) (end_nodes - node.start) : 1.0),
+            way.count / 1000,
+            way.count > 0 ? (double) way.count / 1000.0 / ((double) (end_way - way.start) > 0.0 ? (double) (end_way - way.start) : 1.0) : 0.0, rel.count,
+            rel.count > 0 ? (double) rel.count / ((double) (end_rel - rel.start) > 0.0 ? (double) (end_rel - rel.start) : 1.0) : 0.0);
+}
+
+
+parse_osmium_t::parse_osmium_t(bool extra_attrs,
+                               const boost::optional<std::string> &bbox,
+                               const reprojection *proj, bool do_append,
+                               osmdata_t *osmdata)
+: m_data(osmdata), m_append(do_append), m_attributes(extra_attrs), m_proj(proj)
+{
+    if (bbox) {
+        m_bbox = parse_bbox(bbox);
+    }
+}
+
+osmium::Box parse_osmium_t::parse_bbox(const boost::optional<std::string> &bbox)
+{
+    double minx, maxx, miny, maxy;
+    int n = sscanf(bbox->c_str(), "%lf,%lf,%lf,%lf",
+                   &minx, &miny, &maxx, &maxy);
+    if (n != 4)
+        throw std::runtime_error("Bounding box must be specified like: minlon,minlat,maxlon,maxlat\n");
+
+    if (maxx <= minx)
+        throw std::runtime_error("Bounding box failed due to maxlon <= minlon\n");
+
+    if (maxy <= miny)
+        throw std::runtime_error("Bounding box failed due to maxlat <= minlat\n");
+
+    fprintf(stderr, "Applying Bounding box: %f,%f to %f,%f\n", minx, miny, maxx, maxy);
+
+    return osmium::Box(minx, miny, maxx, maxy);
+}
+
+void parse_osmium_t::stream_file(const std::string &filename, const std::string &fmt)
+{
+    const char* osmium_format = fmt == "auto" ? "" : fmt.c_str();
+    osmium::io::File infile(filename, osmium_format);
+
+    if (infile.format() == osmium::io::file_format::unknown)
+        throw std::runtime_error(fmt.empty()
+                                   ?"Cannot detect file format. Try using -r."
+                                   : ((boost::format("Unknown file format '%1%'.")
+                                                    % fmt).str()));
+
+    fprintf(stderr, "Using %s parser.\n", osmium::io::as_string(infile.format()));
+
+    osmium::io::Reader reader(infile);
+    osmium::apply(reader, *this);
+    reader.close();
+}
+
+void parse_osmium_t::node(osmium::Node& node)
+{
+    if (node.deleted()) {
+        m_data->node_delete(node.id());
+    } else {
+        // if the node is not valid, then node.location.lat/lon() can throw.
+        // we probably ought to treat invalid locations as if they were
+        // deleted and ignore them.
+        if (!node.location().valid()) {
+          fprintf(stderr, "WARNING: Node %" PRIdOSMID " (version %ud) has an invalid "
+                  "location and has been ignored. This is not expected to happen with "
+                  "recent planet files, so please check that your input is correct.\n",
+                  node.id(), node.version());
+
+          return;
+        }
+
+        if (!m_bbox || m_bbox->contains(node.location())) {
+            auto c = m_proj->reproject(node.location());
+
+            convert_tags(node);
+            if (m_append) {
+                m_data->node_modify(node.id(), c.y, c.x, tags);
+            } else {
+                m_data->node_add(node.id(), c.y, c.x, tags);
+            }
+            m_stats.add_node(node.id());
+        }
+    }
+}
+
+void parse_osmium_t::way(osmium::Way& way)
+{
+    if (way.deleted()) {
+        m_data->way_delete(way.id());
+    } else {
+        convert_tags(way);
+        convert_nodes(way.nodes());
+        if (m_append) {
+            m_data->way_modify(way.id(), nds, tags);
+        } else {
+            m_data->way_add(way.id(), nds, tags);
+        }
+    }
+    m_stats.add_way(way.id());
+}
+
+void parse_osmium_t::relation(osmium::Relation& rel)
+{
+    if (rel.deleted()) {
+        m_data->relation_delete(rel.id());
+    } else {
+        convert_tags(rel);
+        convert_members(rel.members());
+        if (m_append) {
+            m_data->relation_modify(rel.id(), members, tags);
+        } else {
+            m_data->relation_add(rel.id(), members, tags);
+        }
+    }
+    m_stats.add_rel(rel.id());
+}
+
+void parse_osmium_t::convert_tags(const osmium::OSMObject &obj)
+{
+    tags.clear();
+    for (auto const &t : obj.tags()) {
+        tags.emplace_back(t.key(), t.value());
+    }
+    if (m_attributes) {
+        tags.emplace_back("osm_user", obj.user());
+        tags.emplace_back("osm_uid", std::to_string(obj.uid()));
+        tags.emplace_back("osm_version", std::to_string(obj.version()));
+        tags.emplace_back("osm_timestamp", obj.timestamp().to_iso());
+        tags.emplace_back("osm_changeset", std::to_string(obj.changeset()));
+    }
+}
+
+void parse_osmium_t::convert_nodes(const osmium::NodeRefList &in_nodes)
+{
+    nds.clear();
+
+    for (auto const &n : in_nodes) {
+        nds.push_back(n.ref());
+    }
+}
+
+void parse_osmium_t::convert_members(const osmium::RelationMemberList &in_rels)
+{
+    members.clear();
+
+    for (auto const &m: in_rels) {
+        OsmType type;
+        switch (m.type()) {
+            case osmium::item_type::node: type = OSMTYPE_NODE; break;
+            case osmium::item_type::way: type = OSMTYPE_WAY; break;
+            case osmium::item_type::relation: type = OSMTYPE_RELATION; break;
+            default:
+                fprintf(stderr, "Unsupported type: %u""\n", unsigned(m.type()));
+        }
+        members.emplace_back(type, m.ref(), m.role());
+    }
+}
diff --git a/parse-osmium.hpp b/parse-osmium.hpp
new file mode 100644
index 0000000..1264ef4
--- /dev/null
+++ b/parse-osmium.hpp
@@ -0,0 +1,145 @@
+/*
+#-----------------------------------------------------------------------------
+# osm2pgsql - converts planet.osm file into PostgreSQL
+# compatible output suitable to be rendered by mapnik
+#-----------------------------------------------------------------------------
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#-----------------------------------------------------------------------------
+*/
+
+#ifndef PARSE_OSMIUM_H
+#define PARSE_OSMIUM_H
+
+#include "config.h"
+
+#include <boost/optional.hpp>
+#include <ctime>
+
+#include "osmtypes.hpp"
+
+#include <osmium/osm/box.hpp>
+#include <osmium/fwd.hpp>
+#include <osmium/handler.hpp>
+
+
+class reprojection;
+class osmdata_t;
+
+class parse_stats_t
+{
+    struct Counter {
+        osmid_t count = 0;
+        osmid_t max = 0;
+        time_t start = 0;
+
+        bool add(osmid_t id, int frac)
+        {
+            if (id > max) {
+                max = id;
+            }
+            if (count == 0) {
+                time(&start);
+            }
+            count++;
+
+            return (count % frac == 0);
+        }
+
+        Counter& operator+=(const Counter& rhs)
+        {
+            count += rhs.count;
+            if (rhs.max > max) {
+                max = rhs.max;
+            }
+            if (start == 0) {
+                start = rhs.start;
+            }
+
+            return *this;
+        }
+    };
+
+public:
+    void update(const parse_stats_t &other);
+    void print_summary() const;
+    void print_status() const;
+
+    inline void add_node(osmid_t id)
+    {
+        if (node.add(id, 10000)) {
+            print_status();
+        }
+    }
+
+    inline void add_way(osmid_t id)
+    {
+        if (way.add(id, 1000)) {
+            print_status();
+        }
+    }
+
+    inline void add_rel(osmid_t id)
+    {
+        if (rel.add(id, 10)) {
+           print_status();
+        }
+    }
+
+private:
+    Counter node, way, rel;
+};
+
+
+class parse_osmium_t: public osmium::handler::Handler
+{
+public:
+    parse_osmium_t(bool extra_attrs, const boost::optional<std::string> &bbox,
+                   const reprojection *proj, bool do_append, osmdata_t *osmdata);
+
+    void stream_file(const std::string &filename, const std::string &fmt);
+
+    void node(osmium::Node& node);
+    void way(osmium::Way& way);
+    void relation(osmium::Relation& rel);
+
+    parse_stats_t const &stats() const
+    {
+        return m_stats;
+    }
+
+private:
+    void convert_tags(const osmium::OSMObject &obj);
+    void convert_nodes(const osmium::NodeRefList &in_nodes);
+    void convert_members(const osmium::RelationMemberList &in_rels);
+
+    osmium::Box parse_bbox(const boost::optional<std::string> &bbox);
+
+    osmdata_t *m_data;
+    bool m_append;
+    boost::optional<osmium::Box> m_bbox;
+    bool m_attributes;
+    const reprojection *m_proj;
+    parse_stats_t m_stats;
+
+    /* Since {node,way} elements are not nested we can guarantee that
+       elements are parsed sequentially and can therefore be cached.
+    */
+    taglist_t tags;
+    idlist_t nds;
+    memberlist_t members;
+};
+
+#endif
diff --git a/parse-pbf.cpp b/parse-pbf.cpp
deleted file mode 100644
index 6405b8e..0000000
--- a/parse-pbf.cpp
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
-#-----------------------------------------------------------------------------
-# osm2pgsql - converts planet.osm file into PostgreSQL
-# compatible output suitable to be rendered by mapnik
-#-----------------------------------------------------------------------------
-# Original Python implementation by Artem Pavlenko
-# Re-implementation by Jon Burgess, Copyright 2006
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# 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 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
-#-----------------------------------------------------------------------------
-*/
-
-#include "config.h"
-
-#ifdef BUILD_READER_PBF
-
-#include <cassert>
-#include <cstdlib>
-#include <stdint.h>
-#include <cstdio>
-#include <cstring>
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <arpa/inet.h>
-#endif
-#include <time.h>
-
-#include <zlib.h>
-#include <string>
-
-#include "parse-pbf.hpp"
-#include "osmdata.hpp"
-#include "osmtypes.hpp"
-#include "reprojection.hpp"
-
-#define MAX_BLOCK_HEADER_SIZE 64*1024
-#define MAX_BLOB_SIZE 32*1024*1024
-
-#define NANO_DEGREE .000000001
-
-static uint32_t get_length(FILE *input)
-{
-  uint32_t buf;
-
-  if (1 != fread(reinterpret_cast<char *>(&buf), sizeof(buf), 1, input))
-    return 0;
-
-  return ntohl(buf);
-}
-
-static BlockHeader *read_header(FILE *input, void *buf)
-{
-  BlockHeader *header_msg;
-  size_t read, length = get_length(input);
-
-  if (length < 1 || length > MAX_BLOCK_HEADER_SIZE) {
-    if (!feof(input)) {
-      fprintf(stderr, "Invalid blocksize %lu\n", (unsigned long)length);
-    }
-    return NULL;
-  }
-
-  read = fread(buf, length, 1, input);
-  if (!read) {
-    perror("parse-pbf: error while reading header data");
-    return NULL;
-  }
-
-  header_msg = block_header__unpack (NULL, length, (const uint8_t *)buf);
-  if (header_msg == NULL) {
-    fprintf(stderr, "Error unpacking BlockHeader message\n");
-    return NULL;
-  }
-
-  return header_msg;
-}
-
-static Blob *read_blob(FILE *input, void *buf, int32_t length)
-{
-  Blob *blob_msg;
-
-  if (length < 1 || length > MAX_BLOB_SIZE) {
-    fprintf(stderr, "Blob isn't present or exceeds minimum/maximum size\n");
-    return NULL;
-  }
-
-  if(1 != fread(buf, length, 1, input)) {
-    fprintf(stderr, "error reading blob content\n");
-    return NULL;
-  }
-
-  blob_msg = blob__unpack (NULL, length, (const uint8_t *)buf);
-  if (blob_msg == NULL) {
-    fprintf(stderr, "Error unpacking Blob message\n");
-    return NULL;
-  }
-
-  return blob_msg;
-}
-
-static size_t uncompress_blob(Blob *bmsg, void *buf, int32_t max_size)
-{
-  if (bmsg->raw_size > max_size) {
-    fprintf(stderr, "blob raw size too large\n");
-    return 0;
-  }
-
-  if (bmsg->has_raw) {
-    memcpy(buf, bmsg->raw.data, bmsg->raw.len);
-    return bmsg->raw.len;
-  } else if (bmsg->has_zlib_data) {
-    int ret;
-    z_stream strm;
-    strm.zalloc = Z_NULL;
-    strm.zfree = Z_NULL;
-    strm.opaque = Z_NULL;
-    strm.avail_in = bmsg->zlib_data.len;
-    strm.next_in = bmsg->zlib_data.data;
-    strm.avail_out = bmsg->raw_size;
-    strm.next_out = (Bytef *)buf;
-
-    ret = inflateInit(&strm);
-    if (ret != Z_OK) {
-      fprintf(stderr, "Zlib init failed\n");
-      return 0;
-    }
-
-    ret = inflate(&strm, Z_NO_FLUSH);
-
-    (void)inflateEnd(&strm);
-
-    if (ret != Z_STREAM_END) {
-      fprintf(stderr, "Zlib compression failed (code %d, %s)\n", ret, strm.msg);
-      return 0;
-    }
-
-    return bmsg->raw_size;
-  } else if (bmsg->has_bzip2_data) {
-    fprintf(stderr, "Can't uncompress bz2 data\n");
-    return 0;
-  } else if (bmsg->has_lzma_data) {
-    fprintf(stderr, "Can't uncompress LZMA data\n");
-    return 0;
-  } else {
-    fprintf(stderr, "We cannot handle the %d non-raw bytes yet...\n", bmsg->raw_size);
-    return 0;
-  }
-
-  return 0;
-}
-
-void parse_pbf_t::addProtobufItem(ProtobufCBinaryData &key,
-                                  ProtobufCBinaryData &val)
-{
-  std::string keystr((const char *) key.data, key.len);
-  assert(keystr.find('\0') == std::string::npos);
-
-  std::string valstr((const char *) val.data, val.len);
-  assert(valstr.find('\0') == std::string::npos);
-
-  tags.push_back(tag(keystr, valstr));
-}
-
-void parse_pbf_t::addIntItem(const char *key, int val)
-{
-  char buf[100];
-  sprintf(buf, "%d", val);
-
-  tags.push_back(tag(key, buf));
-}
-
-void parse_pbf_t::addInfoItems(Info *info, StringTable *string_table)
-{
-  if (info->has_version)
-    addIntItem("osm_version", info->version);
-
-  if (info->has_changeset)
-    addIntItem("osm_changeset", info->changeset);
-
-  if (info->has_uid)
-    addIntItem("osm_uid", info->uid);
-
-  if (info->has_user_sid) {
-    ProtobufCBinaryData user = string_table->s[info->user_sid];
-
-    tags.push_back(tag("osm_user", std::string((const char *) user.data, user.len)));
-  }
-
-  /* TODO timestamp */
-}
-
-static int processOsmHeader(void *data, size_t length)
-{
-  HeaderBlock *hmsg = header_block__unpack (NULL, length, (const uint8_t *)data);
-  if (hmsg == NULL) {
-    fprintf(stderr, "Error unpacking HeaderBlock message\n");
-    return 0;
-  }
-
-  header_block__free_unpacked (hmsg, NULL);
-
-  return 1;
-}
-
-int parse_pbf_t::processOsmDataNodes(osmdata_t *osmdata, PrimitiveGroup *group,
-                                     StringTable *string_table, double lat_offset,
-                                     double lon_offset, double granularity)
-{
-  for (unsigned node_id = 0; node_id < group->n_nodes; node_id++) {
-    Node *node = group->nodes[node_id];
-
-    tags.clear();
-
-    if (node->info && extra_attributes) {
-      addInfoItems(node->info, string_table);
-    }
-
-    for (unsigned key_id = 0; key_id < node->n_keys; key_id++) {
-      addProtobufItem(string_table->s[node->keys[key_id]],
-                      string_table->s[node->vals[key_id]]);
-    }
-
-    double lat = lat_offset + (node->lat * granularity);
-    double lon = lon_offset + (node->lon * granularity);
-    if (node_wanted(lat, lon)) {
-        proj->reproject(&lat, &lon);
-
-        osmdata->node_add(node->id, lat, lon, tags);
-
-        if (node->id > max_node) {
-            max_node = node->id;
-        }
-
-        if (count_node == 0) {
-            time(&start_node);
-        }
-        count_node++;
-        if (count_node%10000 == 0)
-            print_status();
-    }
-  }
-
-  return 1;
-}
-
-int parse_pbf_t::processOsmDataDenseNodes(osmdata_t *osmdata, PrimitiveGroup *group,
-                                          StringTable *string_table,
-                                          double lat_offset, double lon_offset,
-                                          double granularity)
-{
-  if (!group->dense)
-    return 1;
-
-  unsigned l = 0;
-  osmid_t deltaid = 0;
-  long int deltalat = 0;
-  long int deltalon = 0;
-  unsigned long int deltatimestamp = 0;
-  unsigned long int deltachangeset = 0;
-  long int deltauid = 0;
-  unsigned long int deltauser_sid = 0;
-
-  DenseNodes *dense = group->dense;
-
-  for (unsigned node_id = 0; node_id < dense->n_id; node_id++) {
-      tags.clear();
-
-      deltaid += dense->id[node_id];
-      deltalat += dense->lat[node_id];
-      deltalon += dense->lon[node_id];
-
-      if (dense->denseinfo && extra_attributes) {
-          DenseInfo *denseinfo = dense->denseinfo;
-
-          deltatimestamp += denseinfo->timestamp[node_id];
-          deltachangeset += denseinfo->changeset[node_id];
-          deltauid += denseinfo->uid[node_id];
-          deltauser_sid += denseinfo->user_sid[node_id];
-
-          addIntItem("osm_version", denseinfo->version[node_id]);
-          addIntItem("osm_changeset", deltachangeset);
-
-          if (deltauid != -1) { /* osmosis devs failed to read the specs */
-              addIntItem("osm_uid", deltauid);
-              tags.push_back(tag("osm_user",
-                                 std::string((const char *) string_table->s[deltauser_sid].data,
-                                             string_table->s[deltauser_sid].len)));
-          }
-      }
-
-      if (l < dense->n_keys_vals) {
-          while (dense->keys_vals[l] != 0 && l < dense->n_keys_vals) {
-              addProtobufItem(string_table->s[dense->keys_vals[l]],
-                              string_table->s[dense->keys_vals[l+1]]);
-
-              l += 2;
-          }
-          l += 1;
-      }
-
-      double lat = lat_offset + (deltalat * granularity);
-      double lon = lon_offset + (deltalon * granularity);
-      if (node_wanted(lat, lon)) {
-          proj->reproject(&lat, &lon);
-
-          osmdata->node_add(deltaid, lat, lon, tags);
-
-          if (deltaid > max_node) {
-              max_node = deltaid;
-          }
-
-          if (count_node == 0) {
-              time(&start_node);
-          }
-          count_node++;
-          if (count_node%10000 == 0)
-              print_status();
-      }
-  }
-
-  return 1;
-}
-
-int parse_pbf_t::processOsmDataWays(osmdata_t *osmdata, PrimitiveGroup *group,
-                                    StringTable *string_table)
-{
-  for (unsigned way_id = 0; way_id < group->n_ways; way_id++) {
-    Way *way = group->ways[way_id];
-    osmid_t deltaref = 0;
-
-    tags.clear();
-
-    if (way->info && extra_attributes) {
-      addInfoItems(way->info, string_table);
-    }
-
-    nds.clear();
-
-    for (unsigned ref_id = 0; ref_id < way->n_refs; ref_id++) {
-      deltaref += way->refs[ref_id];
-
-      nds.push_back(deltaref);
-    }
-
-    for (unsigned key_id = 0; key_id < way->n_keys; key_id++) {
-      addProtobufItem(string_table->s[way->keys[key_id]],
-                      string_table->s[way->vals[key_id]]);
-    }
-
-    osmdata->way_add(way->id, nds, tags);
-
-    if (way->id > max_way) {
-      max_way = way->id;
-    }
-
-    if (count_way == 0) {
-        time(&start_way);
-    }
-    count_way++;
-    if (count_way%1000 == 0)
-      print_status();
-  }
-
-  return 1;
-}
-
-int parse_pbf_t::processOsmDataRelations(osmdata_t *osmdata, PrimitiveGroup *group,
-                                         StringTable *string_table)
-{
-  for (unsigned rel_id = 0; rel_id < group->n_relations; rel_id++) {
-    Relation *relation = group->relations[rel_id];
-    osmid_t deltamemids = 0;
-
-    tags.clear();
-    members.clear();
-
-    if (relation->info && extra_attributes) {
-      addInfoItems(relation->info, string_table);
-    }
-
-    for (unsigned member_id = 0; member_id < relation->n_memids; member_id++) {
-      ProtobufCBinaryData role =  string_table->s[relation->roles_sid[member_id]];
-
-      deltamemids += relation->memids[member_id];
-
-      OsmType type;
-      switch (relation->types[member_id]) {
-        case RELATION__MEMBER_TYPE__NODE: type = OSMTYPE_NODE; break;
-        case RELATION__MEMBER_TYPE__WAY: type = OSMTYPE_WAY; break;
-        case RELATION__MEMBER_TYPE__RELATION: type = OSMTYPE_RELATION; break;
-        default:
-          fprintf(stderr, "Unsupported type: %u""\n", relation->types[member_id]);
-          return 0;
-      }
-
-      members.push_back(member(type, deltamemids,
-                               std::string((const char *)role.data, role.len)));
-    }
-
-    for (unsigned key_id = 0; key_id < relation->n_keys; key_id++) {
-      addProtobufItem(string_table->s[relation->keys[key_id]],
-                      string_table->s[relation->vals[key_id]]);
-    }
-
-    osmdata->relation_add(relation->id, members, tags);
-
-    if (relation->id > max_rel) {
-      max_rel = relation->id;
-    }
-
-    if (count_rel == 0) {
-        time(&start_rel);
-    }
-    count_rel++;
-    if (count_rel%10 == 0)
-      print_status();
-  }
-
-  return 1;
-}
-
-
-int parse_pbf_t::processOsmData(osmdata_t *osmdata, void *data, size_t length)
-{
-  unsigned int j;
-  double lat_offset, lon_offset, granularity;
-  PrimitiveBlock *pmsg = primitive_block__unpack (NULL, length, (const uint8_t *)data);
-  if (pmsg == NULL) {
-    fprintf(stderr, "Error unpacking PrimitiveBlock message\n");
-    return 0;
-  }
-
-  lat_offset = NANO_DEGREE * pmsg->lat_offset;
-  lon_offset = NANO_DEGREE * pmsg->lon_offset;
-  granularity = NANO_DEGREE * pmsg->granularity;
-
-  for (j = 0; j < pmsg->n_primitivegroup; j++) {
-    PrimitiveGroup *group = pmsg->primitivegroup[j];
-    StringTable *string_table = pmsg->stringtable;
-
-    if (!processOsmDataNodes(osmdata, group, string_table, lat_offset, lon_offset, granularity)) return 0;
-    if (!processOsmDataDenseNodes(osmdata, group, string_table, lat_offset, lon_offset, granularity)) return 0;
-    if (!processOsmDataWays(osmdata, group, string_table)) return 0;
-    if (!processOsmDataRelations(osmdata, group, string_table)) return 0;
-  }
-
-  primitive_block__free_unpacked (pmsg, NULL);
-
-  return 1;
-}
-
-parse_pbf_t::parse_pbf_t(const int extra_attributes_, const bool bbox_, const boost::shared_ptr<reprojection>& projection_,
-		const double minlon, const double minlat, const double maxlon, const double maxlat):
-		parse_t(extra_attributes_, bbox_, projection_, minlon, minlat, maxlon, maxlat)
-{
-
-}
-
-parse_pbf_t::~parse_pbf_t()
-{
-
-}
-
-int parse_pbf_t::streamFile(const char *filename, const int, osmdata_t *osmdata)
-{
-  void *header = NULL;
-  void *blob = NULL;
-  char *data = NULL;
-  FILE *input = NULL;
-  BlockHeader *header_msg = NULL;
-  Blob *blob_msg = NULL;
-  size_t length;
-  int exit_status = EXIT_FAILURE;
-
-  header = malloc(MAX_BLOCK_HEADER_SIZE);
-  if (!header) {
-    fprintf(stderr, "parse-pbf: out of memory allocating header buffer\n");
-    goto err;
-  }
-
-  blob = malloc(MAX_BLOB_SIZE);
-  if (!blob) {
-    fprintf(stderr, "parse-pbf: out of memory allocating blob buffer\n");
-    goto err;
-  }
-
-  data = (char *)malloc(MAX_BLOB_SIZE);
-  if (!data) {
-    fprintf(stderr, "parse-pbf: out of memory allocating data buffer\n");
-    goto err;
-  }
-
-  input = fopen(filename, "rb");
-  if (!input) {
-    fprintf(stderr, "Unable to open %s\n", filename);
-    goto err;
-  }
-
-  do {
-    header_msg = read_header(input, header);
-    if (header_msg == NULL) {
-      break;
-    }
-
-    blob_msg = read_blob(input, blob, header_msg->datasize);
-
-    length = uncompress_blob(blob_msg, data, MAX_BLOB_SIZE);
-    if (!length) {
-      goto err;
-    }
-
-    if (strcmp(header_msg->type, "OSMHeader") == 0) {
-      if (!processOsmHeader(data, length)) {
-	goto err;
-      }
-    } else if (strcmp(header_msg->type, "OSMData") == 0) {
-      if (!processOsmData(osmdata, data, length)) {
-	goto err;
-      }
-    }
-
-    blob__free_unpacked (blob_msg, NULL);
-    block_header__free_unpacked (header_msg, NULL);
-  } while (!feof(input));
-
-  if (!feof(input)) {
-    goto err;
-  }
-
-  exit_status = EXIT_SUCCESS;
-
- err:
-  if (input)  fclose(input);
-
-  if (header) free(header);
-  if (blob)   free(blob);
-  if (data)   free(data);
-
-  return exit_status;
-}
-#endif //BUILD_READER_PBF
diff --git a/parse-pbf.hpp b/parse-pbf.hpp
deleted file mode 100644
index 8a2fc98..0000000
--- a/parse-pbf.hpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-#-----------------------------------------------------------------------------
-# osm2pgsql - converts planet.osm file into PostgreSQL
-# compatible output suitable to be rendered by mapnik
-#-----------------------------------------------------------------------------
-# Original Python implementation by Artem Pavlenko
-# Re-implementation by Jon Burgess, Copyright 2006
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# 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 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
-#-----------------------------------------------------------------------------
-*/
-
-#ifndef PARSE_PBF_H
-#define PARSE_PBF_H
-
-#include "config.h"
-
-#ifdef BUILD_READER_PBF
-extern "C" {
-#include "fileformat.pb-c.h"
-#include "osmformat.pb-c.h"
-}
-
-#include "parse.hpp"
-
-#include <cstddef>
-#include <boost/shared_ptr.hpp>
-
-struct reprojection;
-class osmdata_t;
-
-class parse_pbf_t: public parse_t
-{
-public:
-	parse_pbf_t(const int extra_attributes_, const bool bbox_, const boost::shared_ptr<reprojection>& projection_,
-				const double minlon, const double minlat, const double maxlon, const double maxlat);
-	virtual ~parse_pbf_t();
-	virtual int streamFile(const char *filename, const int sanitize, osmdata_t *osmdata);
-protected:
-	parse_pbf_t();
-	int processOsmDataNodes(osmdata_t *osmdata, PrimitiveGroup *group, StringTable *string_table, double lat_offset, double lon_offset, double granularity);
-	int processOsmDataDenseNodes(osmdata_t *osmdata, PrimitiveGroup *group, StringTable *string_table, double lat_offset, double lon_offset, double granularity);
-	int processOsmDataWays(osmdata_t *osmdata, PrimitiveGroup *group, StringTable *string_table);
-	int processOsmDataRelations(osmdata_t *osmdata, PrimitiveGroup *group, StringTable *string_table);
-	int processOsmData(osmdata_t *osmdata, void *data, size_t length);
-
-private:
-    void addProtobufItem(ProtobufCBinaryData &key, ProtobufCBinaryData &val);
-    void addIntItem(const char *key, int val);
-    void addInfoItems(Info *info, StringTable *string_table);
-};
-
-#endif //BUILD_READER_PBF
-
-#endif
diff --git a/parse-xml2.cpp b/parse-xml2.cpp
deleted file mode 100644
index 49fe259..0000000
--- a/parse-xml2.cpp
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
-#-----------------------------------------------------------------------------
-# osm2pgsql - converts planet.osm file into PostgreSQL
-# compatible output suitable to be rendered by mapnik
-#-----------------------------------------------------------------------------
-# Original Python implementation by Artem Pavlenko
-# Re-implementation by Jon Burgess, Copyright 2006
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# 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 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
-#-----------------------------------------------------------------------------
-*/
-
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <cassert>
-#include <time.h>
-
-#include "sanitizer.hpp"
-#include "input.hpp"
-
-#include "parse-xml2.hpp"
-#include "osmtypes.hpp"
-#include "osmdata.hpp"
-#include "util.hpp"
-#include "reprojection.hpp"
-
-/* Parses the action="foo" tags in JOSM change files. Obvisouly not useful from osmChange files */
-actions_t parse_xml2_t::ParseAction( xmlTextReaderPtr reader)
-{
-    actions_t new_action;
-    xmlChar *action_text;
-    if( filetype == FILETYPE_OSMCHANGE || filetype == FILETYPE_PLANETDIFF )
-        return action;
-    new_action = ACTION_NONE;
-    action_text = xmlTextReaderGetAttribute( reader, BAD_CAST "action" );
-    if( action_text == NULL )
-        new_action = ACTION_CREATE;
-    else if( strcmp((char *)action_text, "modify") == 0 )
-        new_action = ACTION_MODIFY;
-    else if( strcmp((char *)action_text, "delete") == 0 )
-        new_action = ACTION_DELETE;
-    else
-    {
-        fprintf( stderr, "Unknown value for action: %s\n", (char*)action_text );
-        util::exit_nicely();
-    }
-    return new_action;
-}
-
-void parse_xml2_t::SetFiletype(const xmlChar* name, osmdata_t* osmdata)
-{
-	if (xmlStrEqual(name, BAD_CAST "osm"))
-	{
-		filetype = FILETYPE_OSM;
-		action = ACTION_CREATE;
-	}
-	else if (xmlStrEqual(name, BAD_CAST "osmChange"))
-	{
-		filetype = FILETYPE_OSMCHANGE;
-		action = ACTION_NONE;
-	}
-	else if (xmlStrEqual(name, BAD_CAST "planetdiff"))
-	{
-		filetype = FILETYPE_PLANETDIFF;
-		action = ACTION_NONE;
-	}
-	else
-	{
-		fprintf( stderr, "Unknown XML document type: %s\n", name );
-		util::exit_nicely();
-	}
-}
-
-void parse_xml2_t::StartElement(xmlTextReaderPtr reader, const xmlChar *name, osmdata_t *osmdata)
-{
-  xmlChar *xid, *xlat, *xlon, *xk, *xv, *xrole, *xtype;
-
-  //first time in we figure out what kind of data this is
-  if (filetype == FILETYPE_NONE)
-  {
-      SetFiletype(name, osmdata);
-      return;
-  }
-
-  //remember which this was for collecting tags at the end
-  bool can_have_attribs = false;
-
-  if (xmlStrEqual(name, BAD_CAST "node")) {
-    can_have_attribs = true;
-
-    xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
-    xlon = xmlTextReaderGetAttribute(reader, BAD_CAST "lon");
-    xlat = xmlTextReaderGetAttribute(reader, BAD_CAST "lat");
-    assert(xid);
-
-    osm_id   = strtoosmid((char *)xid, NULL, 10);
-    action   = ParseAction(reader);
-
-    if (action != ACTION_DELETE) {
-      assert(xlon); assert(xlat);
-      node_lon = strtod((char *)xlon, NULL);
-      node_lat = strtod((char *)xlat, NULL);
-    }
-
-    if (osm_id > max_node)
-      max_node = osm_id;
-
-    if (count_node == 0) {
-      time(&start_node);
-    }
-    count_node++;
-    if (count_node%10000 == 0)
-      print_status();
-
-    xmlFree(xid);
-    xmlFree(xlon);
-    xmlFree(xlat);
-  } else if (xmlStrEqual(name, BAD_CAST "way")) {
-    can_have_attribs = true;
-
-    xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
-    assert(xid);
-    osm_id   = strtoosmid((char *)xid, NULL, 10);
-    action = ParseAction( reader );
-
-    if (osm_id > max_way)
-      max_way = osm_id;
-
-    if (count_way == 0) {
-      time(&start_way);
-    }
-    count_way++;
-    if (count_way%1000 == 0)
-      print_status();
-
-    nds.clear();
-    xmlFree(xid);
-
-  } else if (xmlStrEqual(name, BAD_CAST "relation")) {
-    can_have_attribs = true;
-
-    xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
-    assert(xid);
-    osm_id   = strtoosmid((char *)xid, NULL, 10);
-    action = ParseAction( reader );
-
-    if (osm_id > max_rel)
-      max_rel = osm_id;
-
-    if (count_rel == 0) {
-      time(&start_rel);
-    }
-    count_rel++;
-    if (count_rel%10 == 0)
-      print_status();
-
-    members.clear();
-    xmlFree(xid);
-  } else if (xmlStrEqual(name, BAD_CAST "tag")) {
-    xk = xmlTextReaderGetAttribute(reader, BAD_CAST "k");
-    assert(xk);
-
-    xv = xmlTextReaderGetAttribute(reader, BAD_CAST "v");
-    assert(xv);
-
-    tags.push_back(tag((const char *)xk, (const char *)xv));
-
-    xmlFree(xv);
-    xmlFree(xk);
-  } else if (xmlStrEqual(name, BAD_CAST "nd")) {
-      xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "ref");
-      assert(xid);
-
-      nds.push_back(strtoosmid( (char *)xid, NULL, 10 ));
-
-      xmlFree(xid);
-  } else if (xmlStrEqual(name, BAD_CAST "member")) {
-    xrole = xmlTextReaderGetAttribute(reader, BAD_CAST "role");
-    assert(xrole);
-
-    xtype = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
-    assert(xtype);
-
-    xid = xmlTextReaderGetAttribute(reader, BAD_CAST "ref");
-    assert(xid);
-
-    OsmType type = OSMTYPE_NODE;
-    if (xmlStrEqual(xtype, BAD_CAST "way"))
-      type = OSMTYPE_WAY;
-    else if (xmlStrEqual(xtype, BAD_CAST "node"))
-      type = OSMTYPE_NODE;
-    else if (xmlStrEqual(xtype, BAD_CAST "relation"))
-      type = OSMTYPE_RELATION;
-
-    members.push_back(member(type, strtoosmid((char *) xid, NULL, 0),
-                             (const char *) xrole));
-    xmlFree(xid);
-    xmlFree(xrole);
-    xmlFree(xtype);
-  } else if (xmlStrEqual(name, BAD_CAST "add") ||
-             xmlStrEqual(name, BAD_CAST "create")) {
-      action = ACTION_MODIFY; /* Turns all creates into modifies, makes it resiliant against inconsistant snapshots. */
-  } else if (xmlStrEqual(name, BAD_CAST "modify")) {
-      action = ACTION_MODIFY;
-  } else if (xmlStrEqual(name, BAD_CAST "delete")) {
-      action = ACTION_DELETE;
-  } else if (xmlStrEqual(name, BAD_CAST "bound")) {
-      /* ignore */
-  } else if (xmlStrEqual(name, BAD_CAST "bounds")) {
-      /* ignore */
-  } else if (xmlStrEqual(name, BAD_CAST "changeset")) {
-      /* ignore */
-  } else {
-      fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
-  }
-
-  /* Collect extra attribute information and add as tags */
-  if (extra_attributes && can_have_attribs)
-  {
-      xmlChar *xtmp;
-
-      xtmp = xmlTextReaderGetAttribute(reader, BAD_CAST "user");
-      if (xtmp) {
-          tags.push_back(tag("osm_user", (const char *)xtmp));
-          xmlFree(xtmp);
-      }
-
-      xtmp = xmlTextReaderGetAttribute(reader, BAD_CAST "uid");
-      if (xtmp) {
-          tags.push_back(tag("osm_uid", (const char *)xtmp));
-          xmlFree(xtmp);
-      }
-
-      xtmp = xmlTextReaderGetAttribute(reader, BAD_CAST "version");
-      if (xtmp) {
-          tags.push_back(tag("osm_version", (const char *)xtmp));
-          xmlFree(xtmp);
-      }
-
-      xtmp = xmlTextReaderGetAttribute(reader, BAD_CAST "timestamp");
-      if (xtmp) {
-          tags.push_back(tag("osm_timestamp", (const char *)xtmp));
-          xmlFree(xtmp);
-      }
-
-      xtmp = xmlTextReaderGetAttribute(reader, BAD_CAST "changeset");
-      if (xtmp) {
-          tags.push_back(tag("osm_changeset", (const char *)xtmp));
-          xmlFree(xtmp);
-      }
-  }
-}
-
-
-void parse_xml2_t::EndElement(const xmlChar *name, osmdata_t *osmdata)
-{
-    if (xmlStrEqual(name, BAD_CAST "node")) {
-        if (node_wanted(node_lat, node_lon)) {
-            proj->reproject(&(node_lat), &(node_lon));
-            if( action == ACTION_CREATE )
-                osmdata->node_add(osm_id, node_lat, node_lon, tags);
-            else if( action == ACTION_MODIFY )
-                osmdata->node_modify(osm_id, node_lat, node_lon, tags);
-            else if( action == ACTION_DELETE )
-                osmdata->node_delete(osm_id);
-            else
-            {
-                fprintf( stderr, "Don't know action for node %" PRIdOSMID "\n", osm_id );
-                util::exit_nicely();
-            }
-        }
-        tags.clear();
-    } else if (xmlStrEqual(name, BAD_CAST "way")) {
-        if( action == ACTION_CREATE )
-            osmdata->way_add(osm_id, nds, tags);
-        else if( action == ACTION_MODIFY )
-            osmdata->way_modify(osm_id, nds, tags);
-        else if( action == ACTION_DELETE )
-            osmdata->way_delete(osm_id);
-        else
-        {
-            fprintf( stderr, "Don't know action for way %" PRIdOSMID "\n", osm_id );
-            util::exit_nicely();
-        }
-        tags.clear();
-    } else if (xmlStrEqual(name, BAD_CAST "relation")) {
-        if( action == ACTION_CREATE )
-            osmdata->relation_add(osm_id, members, tags);
-        else if( action == ACTION_MODIFY )
-            osmdata->relation_modify(osm_id, members, tags);
-        else if( action == ACTION_DELETE )
-            osmdata->relation_delete(osm_id);
-        else
-        {
-            fprintf( stderr, "Don't know action for relation %" PRIdOSMID "\n", osm_id );
-            util::exit_nicely();
-        }
-        tags.clear();
-        members.clear();
-    } else if (xmlStrEqual(name, BAD_CAST "tag")) {
-        /* ignore */
-    } else if (xmlStrEqual(name, BAD_CAST "nd")) {
-        /* ignore */
-    } else if (xmlStrEqual(name, BAD_CAST "member")) {
-	/* ignore */
-    } else if (xmlStrEqual(name, BAD_CAST "osm")) {
-        print_status();
-        filetype = FILETYPE_NONE;
-    } else if (xmlStrEqual(name, BAD_CAST "osmChange")) {
-        print_status();
-        filetype = FILETYPE_NONE;
-    } else if (xmlStrEqual(name, BAD_CAST "planetdiff")) {
-        print_status();
-        filetype = FILETYPE_NONE;
-    } else if (xmlStrEqual(name, BAD_CAST "bound")) {
-        /* ignore */
-    } else if (xmlStrEqual(name, BAD_CAST "bounds")) {
-        /* ignore */
-    } else if (xmlStrEqual(name, BAD_CAST "changeset")) {
-        /* ignore */
-        tags.clear(); /* We may have accumulated some tags even if we ignored the changeset */
-    } else if (xmlStrEqual(name, BAD_CAST "add")) {
-        action = ACTION_NONE;
-    } else if (xmlStrEqual(name, BAD_CAST "create")) {
-        action = ACTION_NONE;
-    } else if (xmlStrEqual(name, BAD_CAST "modify")) {
-        action = ACTION_NONE;
-    } else if (xmlStrEqual(name, BAD_CAST "delete")) {
-        action = ACTION_NONE;
-    } else {
-        fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
-    }
-}
-
-void parse_xml2_t::processNode(xmlTextReaderPtr reader, osmdata_t *osmdata) {
-  xmlChar *name;
-  name = xmlTextReaderName(reader);
-  if (name == NULL)
-    name = xmlStrdup(BAD_CAST "--");
-
-  switch(xmlTextReaderNodeType(reader)) {
-    case XML_READER_TYPE_ELEMENT:
-      StartElement(reader, name, osmdata);
-      if (xmlTextReaderIsEmptyElement(reader))
-        EndElement(name, osmdata); /* No end_element for self closing tags! */
-      break;
-    case XML_READER_TYPE_END_ELEMENT:
-      EndElement(name, osmdata);
-      break;
-    case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
-      /* Ignore */
-      break;
-    default:
-      fprintf(stderr, "Unknown node type %d\n", xmlTextReaderNodeType(reader));
-      break;
-  }
-
-  xmlFree(name);
-}
-
-parse_xml2_t::parse_xml2_t(const int extra_attributes_, const bool bbox_, const boost::shared_ptr<reprojection>& projection_,
-		const double minlon, const double minlat, const double maxlon, const double maxlat):
-		parse_t(extra_attributes_, bbox_, projection_, minlon, minlat, maxlon, maxlat)
-{
-    LIBXML_TEST_VERSION;
-}
-
-parse_xml2_t::~parse_xml2_t()
-{
-    xmlCleanupParser();
-    xmlMemoryDump();
-}
-
-int parse_xml2_t::streamFile(const char *filename, const int sanitize, osmdata_t *osmdata) {
-  xmlTextReaderPtr reader;
-  int ret = 0;
-
-  if (sanitize)
-    reader = sanitizerOpen(filename);
-  else
-    reader = inputUTF8(filename);
-
-  if (reader != NULL) {
-    ret = xmlTextReaderRead(reader);
-    while (ret == 1) {
-      processNode(reader, osmdata);
-      ret = xmlTextReaderRead(reader);
-    }
-
-    if (ret != 0) {
-      fprintf(stderr, "%s : failed to parse\n", filename);
-      return ret;
-    }
-
-    xmlFreeTextReader(reader);
-  } else {
-    fprintf(stderr, "Unable to open %s\n", filename);
-    return 1;
-  }
-  return 0;
-}
diff --git a/parse-xml2.hpp b/parse-xml2.hpp
deleted file mode 100644
index d9cd263..0000000
--- a/parse-xml2.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-#-----------------------------------------------------------------------------
-# osm2pgsql - converts planet.osm file into PostgreSQL
-# compatible output suitable to be rendered by mapnik
-#-----------------------------------------------------------------------------
-# Original Python implementation by Artem Pavlenko
-# Re-implementation by Jon Burgess, Copyright 2006
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# 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 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
-#-----------------------------------------------------------------------------
-*/
-
-#ifndef PARSE_XML2_H
-#define PARSE_XML2_H
-
-/* Open and incrementally read an XML file.
- *
- * Parameters:
- *  - filename: the path to the XML file to stream.
- *  - sanitize: if non-zero, use a parser which attempts to sanitize bad UTF-8
- *      characters.
- *  - osmdata: as the file is parsed, it will call functions on `osmdata->out`
- *      based on the action and type of object, e.g: `node_add`, `relation_modify`,
- *      and so on.
- *
- * Return value: 0 on success. A non-zero value indicates failure.
- */
-
-#include "parse.hpp"
-
-#include <libxml/xmlreader.h>
-
-class parse_xml2_t: public parse_t
-{
-public:
-	parse_xml2_t(const int extra_attributes_, const bool bbox_, const boost::shared_ptr<reprojection>& projection_,
-			const double minlon, const double minlat, const double maxlon, const double maxlat);
-	virtual ~parse_xml2_t();
-	virtual int streamFile(const char *filename, const int sanitize, osmdata_t *osmdata);
-protected:
-	parse_xml2_t();
-	actions_t ParseAction( xmlTextReaderPtr reader);
-	void SetFiletype(const xmlChar* name, osmdata_t* osmdata);
-	void StartElement(xmlTextReaderPtr reader, const xmlChar *name, osmdata_t *osmdata);
-	void EndElement(const xmlChar *name, osmdata_t *osmdata);
-	void processNode(xmlTextReaderPtr reader, osmdata_t *osmdata);
-};
-
-
-#endif
diff --git a/parse.cpp b/parse.cpp
deleted file mode 100644
index f02d463..0000000
--- a/parse.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-#include "config.h"
-#include "parse.hpp"
-#include "parse-o5m.hpp"
-#ifdef BUILD_READER_PBF
-#  include "parse-pbf.hpp"
-#endif
-#include "parse-xml2.hpp"
-
-#include <cstdlib>
-#include <cstdio>
-#include <cstring>
-#include <stdexcept>
-#include <algorithm>
-
-
-#define INIT_MAX_MEMBERS 64
-#define INIT_MAX_NODES  4096
-
-#ifdef _MSC_VER
-#define strcasecmp _stricmp
-#endif
-
-
-parse_delegate_t::parse_delegate_t(const int extra_attributes,
-                                   const boost::optional<std::string> &bbox,
-                                   boost::shared_ptr<reprojection> projection):
-m_extra_attributes(extra_attributes), m_proj(projection), m_count_node(0), m_max_node(0),
-m_count_way(0), m_max_way(0), m_count_rel(0), m_max_rel(0), m_start_node(0), m_start_way(0), m_start_rel(0)
-{
-    m_bbox = bool(bbox);
-    if (m_bbox)
-        parse_bbox(*bbox);
-}
-
-parse_delegate_t::~parse_delegate_t()
-{
-}
-
-int parse_delegate_t::streamFile(const char* input_reader, const char* filename,const int sanitize, osmdata_t *osmdata)
-{
-	//process the input file with the right parser
-	parse_t* parser = get_input_reader(input_reader, filename);
-	int ret = parser->streamFile(filename, sanitize, osmdata);
-
-	//update statisics
-	m_count_node += parser->count_node;
-	m_count_way += parser->count_way;
-	m_count_rel += parser->count_rel;
-	m_max_node = std::max(parser->max_node, m_max_node);
-	m_max_way = std::max(parser->max_way, m_max_way);
-	m_max_rel = std::max(parser->max_rel, m_max_rel);
-	m_start_node = m_start_node == 0 ? parser->start_node : m_start_node;
-	m_start_way = m_start_way == 0 ? parser->start_way : m_start_way;
-	m_start_rel = m_start_rel == 0 ? parser->start_rel : m_start_rel;
-
-	//done
-	delete parser;
-
-	return ret;
-}
-void parse_delegate_t::printSummary() const
-{
-	time_t now = time(NULL);
-	time_t end_nodes = m_start_way > 0 ? m_start_way : now;
-	time_t end_way = m_start_rel > 0 ? m_start_rel : now;
-	time_t end_rel = now;
-
-	fprintf(stderr,
-			"Node stats: total(%" PRIdOSMID "), max(%" PRIdOSMID ") in %is\n",
-			m_count_node, m_max_node,
-			m_count_node > 0 ? (int) (end_nodes - m_start_node) : 0);
-	fprintf(stderr,
-			"Way stats: total(%" PRIdOSMID "), max(%" PRIdOSMID ") in %is\n",
-			m_count_way, m_max_way,
-			m_count_way > 0 ? (int) (end_way - m_start_way) : 0);
-	fprintf(stderr,
-			"Relation stats: total(%" PRIdOSMID "), max(%" PRIdOSMID ") in %is\n",
-			m_count_rel, m_max_rel,
-			m_count_rel > 0 ? (int) (end_rel - m_start_rel) : 0);
-}
-
-boost::shared_ptr<reprojection> parse_delegate_t::getProjection() const
-{
-	return m_proj;
-}
-
-void parse_delegate_t::parse_bbox(const std::string &bbox_)
-{
-    int n = sscanf(bbox_.c_str(), "%lf,%lf,%lf,%lf", &(m_minlon), &(m_minlat), &(m_maxlon), &(m_maxlat));
-    if (n != 4)
-        throw std::runtime_error("Bounding box must be specified like: minlon,minlat,maxlon,maxlat\n");
-
-    if (m_maxlon <= m_minlon)
-        throw std::runtime_error("Bounding box failed due to maxlon <= minlon\n");
-
-    if (m_maxlat <= m_minlat)
-        throw std::runtime_error("Bounding box failed due to maxlat <= minlat\n");
-
-    fprintf(stderr, "Applying Bounding box: %f,%f to %f,%f\n", m_minlon, m_minlat, m_maxlon, m_maxlat);
-}
-
-parse_t* parse_delegate_t::get_input_reader(const char* input_reader, const char* filename)
-{
-	// if input_reader is forced to a specific iput format
-	if (strcmp("auto", input_reader) != 0) {
-		if (strcmp("libxml2", input_reader) == 0) {
-			return new parse_xml2_t(m_extra_attributes, m_bbox, m_proj, m_minlon, m_minlat, m_maxlon, m_maxlat);
-		} else if (strcmp("primitive", input_reader) == 0) {
-      // The more robust libxml2 parser can be used instead of primitive
-			return new parse_xml2_t(m_extra_attributes, m_bbox, m_proj, m_minlon, m_minlat, m_maxlon, m_maxlat);
-#ifdef BUILD_READER_PBF
-		} else if (strcmp("pbf", input_reader) == 0) {
-			return new parse_pbf_t(m_extra_attributes, m_bbox, m_proj, m_minlon, m_minlat, m_maxlon, m_maxlat);
-#endif
-		} else if (strcmp("o5m", input_reader) == 0) {
-			return new parse_o5m_t(m_extra_attributes, m_bbox, m_proj, m_minlon, m_minlat, m_maxlon, m_maxlat);
-		} else {
-			fprintf(stderr, "Input parser `%s' not recognised. Should be one of [libxml2, o5m"
-#ifdef BUILD_READER_PBF
-							", pbf"
-#endif
-							"].\n", input_reader);
-			exit(EXIT_FAILURE);
-		}
-	} // if input_reader is not forced by -r switch try to auto-detect it by file extension
-	else {
-		if (strcasecmp(".pbf", filename + strlen(filename) - 4) == 0) {
-#ifdef BUILD_READER_PBF
-			return new parse_pbf_t(m_extra_attributes, m_bbox, m_proj, m_minlon, m_minlat, m_maxlon, m_maxlat);
-#else
-			fprintf(stderr, "ERROR: PBF support has not been compiled into this version of osm2pgsql, please either compile it with pbf support or use one of the other input formats\n");
-			exit(EXIT_FAILURE);
-#endif
-		} else if (strcasecmp(".o5m", filename + strlen(filename) - 4) == 0
-				|| strcasecmp(".o5c", filename + strlen(filename) - 4) == 0) {
-			return new parse_o5m_t(m_extra_attributes, m_bbox, m_proj, m_minlon, m_minlat, m_maxlon, m_maxlat);
-		} else {
-			return new parse_xml2_t(m_extra_attributes, m_bbox, m_proj, m_minlon, m_minlat, m_maxlon, m_maxlat);
-		}
-	}
-}
-
-
-
-parse_t::parse_t(const int extra_attributes_, const bool bbox_, const boost::shared_ptr<reprojection>& projection_,
-	const double minlon_, const double minlat_, const double maxlon_, const double maxlat_):
-		extra_attributes(extra_attributes_), bbox(bbox_), minlon(minlon_), minlat(minlat_),
-		maxlon(maxlon_), maxlat(maxlat_), proj(projection_)
-{
-	osm_id = count_node = max_node = count_way = max_way = count_rel = 0;
-	max_rel = parallel_indexing = start_node = start_way = start_rel = 0;
-	node_lon = node_lat = 0;
-
-	filetype = FILETYPE_NONE;
-	action   = ACTION_NONE;
-}
-
-parse_t::~parse_t()
-{
-}
-
-
-void parse_t::print_status()
-{
-	time_t now = time(NULL);
-	time_t end_nodes = start_way > 0 ? start_way : now;
-	time_t end_way = start_rel > 0 ? start_rel : now;
-	time_t end_rel = now;
-	fprintf(stderr,
-			"\rProcessing: Node(%" PRIdOSMID "k %.1fk/s) Way(%" PRIdOSMID "k %.2fk/s) Relation(%" PRIdOSMID " %.2f/s)",
-			count_node / 1000,
-			(double) count_node / 1000.0 / ((int) (end_nodes - start_node) > 0 ? (double) (end_nodes - start_node) : 1.0),
-			count_way / 1000,
-			count_way > 0 ?	(double) count_way / 1000.0	/ ((double) (end_way - start_way) > 0.0 ? (double) (end_way - start_way) : 1.0) : 0.0, count_rel,
-			count_rel > 0 ?	(double) count_rel / ((double) (end_rel - start_rel) > 0.0 ? (double) (end_rel - start_rel) : 1.0) : 0.0);
-}
-
-
diff --git a/parse.hpp b/parse.hpp
deleted file mode 100644
index 6e3aeb2..0000000
--- a/parse.hpp
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifndef PARSE_H
-#define PARSE_H
-
-#include "osmtypes.hpp"
-
-#include <time.h>
-#include <string>
-#include <boost/shared_ptr.hpp>
-#include <boost/optional.hpp>
-
-typedef enum { FILETYPE_NONE, FILETYPE_OSM, FILETYPE_OSMCHANGE, FILETYPE_PLANETDIFF } filetypes_t;
-typedef enum { ACTION_NONE, ACTION_CREATE, ACTION_MODIFY, ACTION_DELETE } actions_t;
-
-class parse_t;
-class osmdata_t;
-struct reprojection;
-
-class parse_delegate_t
-{
-public:
-    parse_delegate_t(const int extra_attributes, const boost::optional<std::string> &bbox, boost::shared_ptr<reprojection> projection);
-	~parse_delegate_t();
-
-	int streamFile(const char* input_reader, const char* filename, const int sanitize, osmdata_t *osmdata);
-	void printSummary() const;
-	boost::shared_ptr<reprojection> getProjection() const;
-
-private:
-	parse_delegate_t();
-        void parse_bbox(const std::string &bbox);
-	parse_t* get_input_reader(const char* input_reader, const char* filename);
-
-	const int m_extra_attributes;
-	boost::shared_ptr<reprojection> m_proj;
-	osmid_t m_count_node, m_max_node;
-	osmid_t m_count_way,  m_max_way;
-	osmid_t m_count_rel,  m_max_rel;
-	time_t  m_start_node, m_start_way, m_start_rel;
-
-	bool m_bbox;
-	double m_minlon, m_minlat, m_maxlon, m_maxlat;
-};
-
-class parse_t
-{
-	friend class parse_delegate_t;
-
-public:
-	parse_t(const int extra_attributes_, const bool bbox_, const boost::shared_ptr<reprojection>& projection_,
-			const double minlon, const double minlat, const double maxlon, const double maxlat);
-	virtual ~parse_t();
-
-	virtual int streamFile(const char *filename, const int sanitize, osmdata_t *osmdata) = 0;
-
-protected:
-    parse_t();
-
-    void print_status();
-
-    int node_wanted(double lat, double lon)
-    {
-        if (!bbox)
-            return 1;
-
-        if (lat < minlat || lat > maxlat)
-            return 0;
-        if (lon < minlon || lon > maxlon)
-            return 0;
-        return 1;
-    }
-
-	osmid_t count_node,    max_node;
-	osmid_t count_way,     max_way;
-	osmid_t count_rel,     max_rel;
-	time_t  start_node, start_way, start_rel;
-
-    /* Since {node,way} elements are not nested we can guarantee the
-    values in an end tag must match those of the corresponding
-    start tag and can therefore be cached.
-    */
-    double node_lon, node_lat;
-    taglist_t tags;
-    idlist_t nds;
-    memberlist_t members;
-    osmid_t osm_id;
-    filetypes_t filetype;
-    actions_t action;
-    int parallel_indexing;
-
-	const int extra_attributes;
-	mutable bool bbox;
-	mutable double minlon, minlat, maxlon, maxlat;
-	const boost::shared_ptr<reprojection> proj;
-};
-
-#endif
diff --git a/pgsql.cpp b/pgsql.cpp
index 847ab8a..3136adb 100644
--- a/pgsql.cpp
+++ b/pgsql.cpp
@@ -4,13 +4,12 @@
 #include <cstdio>
 #include <cstdlib>
 #include <cstdarg>
+#include <memory>
 #include <boost/format.hpp>
-#include <boost/foreach.hpp>
 
 void escape(const std::string &src, std::string &dst)
 {
-    BOOST_FOREACH(const char c, src)
-    {
+    for (const char c: src) {
         switch(c) {
             case '\\':  dst.append("\\\\"); break;
             //case 8:   dst.append("\\\b"); break;
@@ -25,12 +24,12 @@ void escape(const std::string &src, std::string &dst)
 }
 
 
-boost::shared_ptr<PGresult> pgsql_exec_simple(PGconn *sql_conn, const ExecStatusType expect, const std::string& sql)
+std::shared_ptr<PGresult> pgsql_exec_simple(PGconn *sql_conn, const ExecStatusType expect, const std::string& sql)
 {
     return pgsql_exec_simple(sql_conn, expect, sql.c_str());
 }
 
-boost::shared_ptr<PGresult> pgsql_exec_simple(PGconn *sql_conn, const ExecStatusType expect, const char *sql)
+std::shared_ptr<PGresult> pgsql_exec_simple(PGconn *sql_conn, const ExecStatusType expect, const char *sql)
 {
     PGresult* res;
 #ifdef DEBUG_PGSQL
@@ -41,7 +40,7 @@ boost::shared_ptr<PGresult> pgsql_exec_simple(PGconn *sql_conn, const ExecStatus
         PQclear(res);
         throw std::runtime_error((boost::format("%1% failed: %2%\n") % sql % PQerrorMessage(sql_conn)).str());
     }
-    return boost::shared_ptr<PGresult>(res, &PQclear);
+    return std::shared_ptr<PGresult>(res, &PQclear);
 }
 
 int pgsql_exec(PGconn *sql_conn, const ExecStatusType expect, const char *fmt, ...)
@@ -54,7 +53,7 @@ int pgsql_exec(PGconn *sql_conn, const ExecStatusType expect, const char *fmt, .
     /* Based on vprintf manual page */
     /* Guess we need no more than 100 bytes. */
 
-    if ((sql = (char *)malloc(size)) == NULL)
+    if ((sql = (char *)malloc(size)) == nullptr)
         throw std::runtime_error("Memory allocation failed in pgsql_exec");
 
     while (1) {
@@ -70,7 +69,7 @@ int pgsql_exec(PGconn *sql_conn, const ExecStatusType expect, const char *fmt, .
             size = n+1; /* precisely what is needed */
         else           /* glibc 2.0 */
             size *= 2;  /* twice the old size */
-        if ((nsql = (char *)realloc (sql, size)) == NULL) {
+        if ((nsql = (char *)realloc (sql, size)) == nullptr) {
             free(sql);
             throw std::runtime_error("Memory re-allocation failed in pgsql_exec");
         } else {
@@ -119,7 +118,7 @@ PGresult *pgsql_execPrepared( PGconn *sql_conn, const char *stmtName, const int
     fprintf( stderr, "ExecPrepared: %s\n", stmtName );
 #endif
     //run the prepared statement
-    PGresult *res = PQexecPrepared(sql_conn, stmtName, nParams, paramValues, NULL, NULL, 0);
+    PGresult *res = PQexecPrepared(sql_conn, stmtName, nParams, paramValues, nullptr, nullptr, 0);
     if(PQresultStatus(res) != expect)
     {
         std::string message = (boost::format("%1% failed: %2%(%3%)\n") % stmtName % PQerrorMessage(sql_conn) % PQresultStatus(res)).str();
@@ -141,7 +140,7 @@ PGresult *pgsql_execPrepared( PGconn *sql_conn, const char *stmtName, const int
     if( expect != PGRES_TUPLES_OK )
     {
         PQclear(res);
-        res = NULL;
+        res = nullptr;
     }
     return res;
 }
diff --git a/pgsql.hpp b/pgsql.hpp
index 684ad1c..01c5b50 100644
--- a/pgsql.hpp
+++ b/pgsql.hpp
@@ -9,12 +9,12 @@
 #include <string>
 #include <cstring>
 #include <libpq-fe.h>
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
 PGresult *pgsql_execPrepared( PGconn *sql_conn, const char *stmtName, const int nParams, const char *const * paramValues, const ExecStatusType expect);
 void pgsql_CopyData(const char *context, PGconn *sql_conn, const char *sql, int len);
-boost::shared_ptr<PGresult> pgsql_exec_simple(PGconn *sql_conn, const ExecStatusType expect, const std::string& sql);
-boost::shared_ptr<PGresult> pgsql_exec_simple(PGconn *sql_conn, const ExecStatusType expect, const char *sql);
+std::shared_ptr<PGresult> pgsql_exec_simple(PGconn *sql_conn, const ExecStatusType expect, const std::string& sql);
+std::shared_ptr<PGresult> pgsql_exec_simple(PGconn *sql_conn, const ExecStatusType expect, const char *sql);
 int pgsql_exec(PGconn *sql_conn, const ExecStatusType expect, const char *fmt, ...)
 #ifndef _MSC_VER
  __attribute__ ((format (printf, 3, 4)))
@@ -25,10 +25,10 @@ void escape(const std::string &src, std::string& dst);
 
 
 inline void pgsql_CopyData(const char *context, PGconn *sql_conn, const char *sql) {
-    pgsql_CopyData(context, sql_conn, sql, strlen(sql));
+    pgsql_CopyData(context, sql_conn, sql, (int) strlen(sql));
 }
 
 inline void pgsql_CopyData(const char *context, PGconn *sql_conn, const std::string &sql) {
-    pgsql_CopyData(context, sql_conn, sql.c_str(), sql.length());
+    pgsql_CopyData(context, sql_conn, sql.c_str(), (int) sql.length());
 }
 #endif
diff --git a/processor-line.cpp b/processor-line.cpp
index 7ac7cd8..d979c42 100644
--- a/processor-line.cpp
+++ b/processor-line.cpp
@@ -8,10 +8,7 @@ processor_line::~processor_line()
 {
 }
 
-geometry_builder::maybe_wkt_t processor_line::process_way(const nodelist_t &nodes)
+geometry_builder::pg_geom_t processor_line::process_way(const nodelist_t &nodes)
 {
-    //have the builder make the wkt
-    geometry_builder::maybe_wkt_t wkt = builder.get_wkt_simple(nodes, false);
-    //hand back the wkt
-    return wkt;
+    return builder.get_wkb_simple(nodes, false);
 }
diff --git a/processor-line.hpp b/processor-line.hpp
index f385fcd..782fee5 100644
--- a/processor-line.hpp
+++ b/processor-line.hpp
@@ -7,7 +7,7 @@ struct processor_line : public geometry_processor {
     processor_line(int srid);
     virtual ~processor_line();
 
-    geometry_builder::maybe_wkt_t process_way(const nodelist_t &nodes);
+    geometry_builder::pg_geom_t process_way(const nodelist_t &nodes);
 
 private:
     geometry_builder builder;
diff --git a/processor-point.cpp b/processor-point.cpp
index 4eab45d..d404725 100644
--- a/processor-point.cpp
+++ b/processor-point.cpp
@@ -1,9 +1,10 @@
-#include "config.h" // for FIXED_POINT
-#include "processor-point.hpp"
-#include "util.hpp"
+#include <memory>
 
 #include <boost/format.hpp>
 
+#include "processor-point.hpp"
+#include "util.hpp"
+
 processor_point::processor_point(int srid)
     : geometry_processor(srid, "POINT", interest_node) {
 }
@@ -11,8 +12,7 @@ processor_point::processor_point(int srid)
 processor_point::~processor_point() {
 }
 
-geometry_builder::maybe_wkt_t processor_point::process_node(double lat, double lon) {
-    geometry_builder::maybe_wkt_t wkt(new geometry_builder::wkt_t());
-    wkt->geom = (boost::format("POINT(%.15g %.15g)") % lon % lat).str();
-    return wkt;
+geometry_builder::pg_geom_t processor_point::process_node(double lat, double lon)
+{
+    return geometry_builder::pg_geom_t((boost::format("POINT(%.15g %.15g)") % lon % lat).str(), false);
 }
diff --git a/processor-point.hpp b/processor-point.hpp
index 55b9ebd..6cdf58e 100644
--- a/processor-point.hpp
+++ b/processor-point.hpp
@@ -7,7 +7,7 @@ struct processor_point : public geometry_processor {
     processor_point(int srid);
     virtual ~processor_point();
 
-    geometry_builder::maybe_wkt_t process_node(double lat, double lon);
+    geometry_builder::pg_geom_t process_node(double lat, double lon);
 };
 
 #endif /* PROCESSOR_POINT_HPP */
diff --git a/processor-polygon.cpp b/processor-polygon.cpp
index 95b9ff1..73c3392 100644
--- a/processor-polygon.cpp
+++ b/processor-polygon.cpp
@@ -8,17 +8,12 @@ processor_polygon::~processor_polygon()
 {
 }
 
-geometry_builder::maybe_wkt_t processor_polygon::process_way(const nodelist_t &nodes)
+geometry_builder::pg_geom_t processor_polygon::process_way(const nodelist_t &nodes)
 {
-    //have the builder make the wkt
-    geometry_builder::maybe_wkt_t wkt = builder.get_wkt_simple(nodes, true);
-    //hand back the wkt
-    return wkt;
+    return builder.get_wkb_simple(nodes, true);
 }
 
-geometry_builder::maybe_wkts_t processor_polygon::process_relation(const multinodelist_t &nodes)
+geometry_builder::pg_geoms_t processor_polygon::process_relation(const multinodelist_t &nodes)
 {
-    //the hard word was already done for us in getting at the node data for each way. at this point just make the geom
-    geometry_builder::maybe_wkts_t wkts  = builder.build_polygons(nodes, enable_multi, -1);
-    return wkts;
+    return  builder.build_polygons(nodes, enable_multi, -1);
 }
diff --git a/processor-polygon.hpp b/processor-polygon.hpp
index e19181d..6d562eb 100644
--- a/processor-polygon.hpp
+++ b/processor-polygon.hpp
@@ -7,8 +7,8 @@ struct processor_polygon : public geometry_processor {
     processor_polygon(int srid, bool enable_multi);
     virtual ~processor_polygon();
 
-    geometry_builder::maybe_wkt_t process_way(const nodelist_t &nodes);
-    geometry_builder::maybe_wkts_t process_relation(const multinodelist_t &nodes);
+    geometry_builder::pg_geom_t process_way(const nodelist_t &nodes);
+    geometry_builder::pg_geoms_t process_relation(const multinodelist_t &nodes);
 
 private:
     bool enable_multi;
diff --git a/protobuf/fileformat.proto b/protobuf/fileformat.proto
deleted file mode 100644
index 73e7d79..0000000
--- a/protobuf/fileformat.proto
+++ /dev/null
@@ -1,30 +0,0 @@
-option java_package = "crosby.binary";
-//protoc --java_out=../.. fileformat.proto
-
-
-//
-//  STORAGE LAYER: Storing primitives.
-//
-
-message Blob {
-  optional bytes raw = 1; // No compression
-  optional int32 raw_size = 2; // When compressed, the uncompressed size
-  // Possible compressed versions of the data.
-  optional bytes zlib_data = 3;
-  optional bytes lzma_data = 4;
-  optional bytes bzip2_data = 5;
-}
-
-/* A file contains an sequence of fileblock headers, each prefixed by
-their length, followed by a data block containing the actual data. 
-types staring with a "_" are reserved.
-
-*/
-
-message BlockHeader {
-  required string type = 1;
-  optional bytes indexdata = 2;
-  required int32 datasize = 3;
-}
-
-
diff --git a/protobuf/osmformat.proto b/protobuf/osmformat.proto
deleted file mode 100644
index f18bc01..0000000
--- a/protobuf/osmformat.proto
+++ /dev/null
@@ -1,206 +0,0 @@
-option java_package = "crosby.binary";
-
-/* OSM Binary file format 
-
-This is the master schema file of the OSM binary file format. This
-file is designed to support limited random-access and future
-extendability.
-
-A binary OSM file consists of a sequence of FileBlocks (please see
-fileformat.proto). The first fileblock contains a serialized instance
-of HeaderBlock, followed by a sequence of PrimitiveBlock blocks that
-contain the primitives.
-
-Each primitiveblock is designed to be independently parsable. It
-contains a string table storing all strings in that block (keys and
-values in tags, roles in relations, usernames, etc.) as well as
-metadata containing the precision of coordinates or timestamps in that
-block.
-
-A primitiveblock contains a sequence of primitive groups, each
-containing primitives of the same type (nodes, densenodes, ways,
-relations). Coordinates are stored in signed 64-bit integers. Lat&lon
-are measured in units <granularity> nanodegrees. The default of
-granularity of 100 nanodegrees corresponds to about 1cm on the ground,
-and a full lat or lon fits into 32 bits.
-
-Converting an integer to a lattitude or longitude uses the formula:
-$OUT = IN * granularity / 10**9$. Many encoding schemes use delta
-coding when representing nodes and relations.
-
-*/
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-
-/* Contains the file header. */
-
-message HeaderBlock {
-  optional HeaderBBox bbox = 1;
-  /* Additional tags to aid in parsing this dataset */
-  repeated string required_features = 4;
-  repeated string optional_features = 5;
-
-  optional string writingprogram = 16; 
-  optional string source = 17; // From the bbox field.
-}
-
-
-/** The bounding box field in the OSM header. BBOX, as used in the OSM
-header. Units are always in nanodegrees -- they do not obey
-granularity rules. */
-
-message HeaderBBox {
-   required sint64 left = 1;
-   required sint64 right = 2;
-   required sint64 top = 3;
-   required sint64 bottom = 4;
-}
-
-
-///////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////
-
-
-message PrimitiveBlock {
-  required StringTable stringtable = 1;
-  repeated PrimitiveGroup primitivegroup = 2;
-
-  // Granularity, units of nanodegrees, used to store coordinates in this block
-  optional int32 granularity = 17 [default=100]; 
-  // Offset value between the output coordinates coordinates and the granularity grid in unites of nanodegrees.
-  optional int64 lat_offset = 19 [default=0];
-  optional int64 lon_offset = 20 [default=0]; 
-
-// Granularity of dates, normally represented in units of milliseconds since the 1970 epoch.
-  optional int32 date_granularity = 18 [default=1000]; 
-
-
-  // Proposed extension:
-  //optional BBox bbox = 19;
-}
-
-// Group of OSMPrimitives. All primitives in a group must be the same type.
-message PrimitiveGroup {
-  repeated Node     nodes = 1;
-  optional DenseNodes dense = 2;
-  repeated Way      ways = 3;
-  repeated Relation relations = 4;
-  repeated ChangeSet changesets = 5;
-}
-
-
-/** String table, contains the common strings in each block.
-
- Note that we reserve index '0' as a delimiter, so the entry at that
- index in the table is ALWAYS blank and unused.
-
- */
-message StringTable {
-   repeated bytes s = 1;
-}
-
-/* Optional metadata that may be included into each primitive. */
-message Info {
-   optional int32 version = 1 [default = -1];
-   optional int32 timestamp = 2;
-   optional int64 changeset = 3;
-   optional int32 uid = 4;
-   optional int32 user_sid = 5; // String IDs
-}
-
-/** Optional metadata that may be included into each primitive. Special dense format used in DenseNodes. */
-message DenseInfo {
-   repeated int32 version = 1 [packed = true]; 
-   repeated sint64 timestamp = 2 [packed = true]; // DELTA coded
-   repeated sint64 changeset = 3 [packed = true]; // DELTA coded
-   repeated sint32 uid = 4 [packed = true]; // DELTA coded
-   repeated sint32 user_sid = 5 [packed = true]; // String IDs for usernames. DELTA coded
-}
-
-
-// TODO: REMOVE THIS? NOT in osmosis schema.
-message ChangeSet {
-   required int64 id = 1;
-   // Parallel arrays.
-   repeated uint32 keys = 2 [packed = true]; // String IDs.
-   repeated uint32 vals = 3 [packed = true]; // String IDs.
-
-   optional Info info = 4;
-
-   required int64 created_at = 8;
-   optional int64 closetime_delta = 9;
-   required bool open = 10;
-   optional HeaderBBox bbox = 11;
-}
-
-
-message Node {
-   required sint64 id = 1;
-   // Parallel arrays.
-   repeated uint32 keys = 2 [packed = true]; // String IDs.
-   repeated uint32 vals = 3 [packed = true]; // String IDs.
-
-   optional Info info = 4; // May be omitted in omitmeta
-
-   required sint64 lat = 8;
-   required sint64 lon = 9;
-}
-
-/* Used to densly represent a sequence of nodes that do not have any tags.
-
-We represent these nodes columnwise as five columns: ID's, lats, and
-lons, all delta coded. When metadata is not omitted, 
-
-We encode keys & vals for all nodes as a single array of integers
-containing key-stringid and val-stringid, using a stringid of 0 as a
-delimiter between nodes.
-
-   ( (<keyid> <valid>)* '0' )*
- */
-
-message DenseNodes {
-   repeated sint64 id = 1 [packed = true]; // DELTA coded
-
-   //repeated Info info = 4;
-   optional DenseInfo denseinfo = 5;
-
-   repeated sint64 lat = 8 [packed = true]; // DELTA coded
-   repeated sint64 lon = 9 [packed = true]; // DELTA coded
-
-   // Special packing of keys and vals into one array. May be empty if all nodes in this block are tagless.
-   repeated int32 keys_vals = 10 [packed = true]; 
-}
-
-
-message Way {
-   required int64 id = 1;
-   // Parallel arrays.
-   repeated uint32 keys = 2 [packed = true];
-   repeated uint32 vals = 3 [packed = true];
-
-   optional Info info = 4;
-
-   repeated sint64 refs = 8 [packed = true];  // DELTA coded
-}
-
-message Relation {
-  enum MemberType {
-    NODE = 0;
-    WAY = 1;
-    RELATION = 2;
-  } 
-   required int64 id = 1;
-
-   // Parallel arrays.
-   repeated uint32 keys = 2 [packed = true];
-   repeated uint32 vals = 3 [packed = true];
-
-   optional Info info = 4;
-
-   // Parallel arrays
-   repeated int32 roles_sid = 8 [packed = true];
-   repeated sint64 memids = 9 [packed = true]; // DELTA encoded
-   repeated MemberType types = 10 [packed = true];
-}
-
diff --git a/reprojection.cpp b/reprojection.cpp
index 276f61d..3dd7f48 100644
--- a/reprojection.cpp
+++ b/reprojection.cpp
@@ -7,199 +7,130 @@
 
 #include "config.h"
 
-#include <cstdlib>
 #include <cstdio>
+#include <cstdlib>
 #include <cstring>
-#include <proj_api.h>
-#include <cmath>
 
 #include "reprojection.hpp"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 /** must match expire.tiles.c */
 #define EARTH_CIRCUMFERENCE              40075016.68
 
-Projection_Info::Projection_Info(const char *descr_, const char *proj4text_, int srs_, const char *option_)
-    : descr(descr_), proj4text(proj4text_), srs(srs_), option(option_) {
-}
-
 namespace {
 
-const struct Projection_Info Projection_Infos[] = {
-    /*PROJ_LATLONG*/ Projection_Info(
-        /*descr    */ "Latlong",
-        /*proj4text*/ "+init=epsg:4326",
-        /*srs      */ 4326,
-        /*option   */ "-l" ),
-    /*PROJ_SPHERE_MERC*/ Projection_Info(
-        /*descr    */ "Spherical Mercator",
-        /*proj4text*/ "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs",
-        /*srs      */ 900913,
-        /*option   */ "-m" )
-};
-
-} // anonymous namespace
-
-/* Positive numbers refer the to the table above, negative numbers are
-   assumed to refer to EPSG codes and it uses the proj4 to find those. */
-reprojection::reprojection(int proj)
-    : Proj(proj), pj_source(NULL), pj_target(NULL), pj_tile(NULL),
-      custom_projection(NULL)
+void latlon2merc(double *lat, double *lon)
 {
-    char buffer[32];
-
-    /* hard-code the source projection to be lat/lon, since OSM XML always
-     * has coordinates in degrees. */
-    pj_source = pj_init_plus("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
-
-    /* hard-code the tile projection to be spherical mercator always.
-     * theoretically this could be made selectable but not all projections
-     * lend themselves well to making tiles; non-spherical mercator tiles
-     * are uncharted waters in OSM. */
-    pj_tile = pj_init_plus(Projection_Infos[PROJ_SPHERE_MERC].proj4text);
+    if (*lat > 85.07)
+        *lat = 85.07;
+    else if (*lat < -85.07)
+        *lat = -85.07;
+
+    using namespace osmium::geom;
+    *lon = (*lon) * EARTH_CIRCUMFERENCE / 360.0;
+    *lat = log(tan(PI/4.0 + deg_to_rad(*lat) / 2.0)) * EARTH_CIRCUMFERENCE/(PI*2);
+}
 
-    /* now set the target projection - the only one which is really variable */
-    if (proj >= 0 && proj < PROJ_COUNT)
-    {
-        pj_target = pj_init_plus(Projection_Infos[proj].proj4text);
-    }
-    else if (proj < 0)
+class latlon_reprojection_t : public reprojection
+{
+public:
+    osmium::geom::Coordinates reproject(osmium::Location loc) const override
     {
-        if (snprintf(buffer, sizeof(buffer), "+init=epsg:%d", -proj ) >= (int)sizeof(buffer))
-        {
-            fprintf(stderr, "Buffer overflow computing proj4 initialisation string\n");
-            exit(1);
-        }
-        pj_target = pj_init_plus(buffer);
-        if (!pj_target)
-        {
-            fprintf (stderr, "Couldn't read EPSG definition (do you have /usr/share/proj/epsg?)\n");
-            exit(1);
-        }
+        return osmium::geom::Coordinates(loc.lon_without_check(),
+                                         loc.lat_without_check());
     }
 
-    if (!pj_source || !pj_target || !pj_tile)
+    void target_to_tile(double *lat, double *lon) const override
     {
-        fprintf(stderr, "Projection code failed to initialise\n");
-        exit(1);
+        latlon2merc(lat, lon);
     }
 
-    if (proj >= 0)
-        return;
+    int target_srs() const override { return PROJ_LATLONG; }
+    const char *target_desc() const override { return "Latlong"; }
+};
 
-    if (snprintf(buffer, sizeof(buffer), "EPSG:%d", -proj) >= (int)sizeof(buffer))
+class merc_reprojection_t : public reprojection
+{
+public:
+    osmium::geom::Coordinates reproject(osmium::Location loc) const override
     {
-        fprintf(stderr, "Buffer overflow computing projection description\n");
-        exit(1);
-    }
-    custom_projection = new Projection_Info(
-        strdup(buffer),
-        pj_get_def(pj_target, 0),
-        -proj, "-E");
-}
+        /* The latitude co-ordinate is clipped at slightly larger than the 900913 'world'
+         * extent of +-85.0511 degrees to ensure that the points appear just outside the
+         * edge of the map. */
+        double lat = loc.lat_without_check();
+        double lon = loc.lon_without_check();
 
-reprojection::~reprojection()
-{
-    pj_free(pj_source);
-    pj_source = NULL;
-    pj_free(pj_target);
-    pj_target = NULL;
-    pj_free(pj_tile);
-    pj_tile = NULL;
-
-    if (custom_projection != NULL) {
-        delete custom_projection;
-    }
-}
+        latlon2merc(&lat, &lon);
 
-struct Projection_Info const *reprojection::project_getprojinfo(void)
-{
-  if( Proj >= 0 )
-    return &Projection_Infos[Proj];
-  else
-    return custom_projection;
-}
+        return osmium::geom::Coordinates(lon, lat);
+    }
 
-void reprojection::reproject(double *lat, double *lon)
-{
-    double x[1], y[1], z[1];
+    void target_to_tile(double *, double *) const override
+    { /* nothing */ }
 
-    /** Caution: This section is only correct if the source projection is lat/lon;
-     *  so even if it looks like pj_source was just a variable, things break if
-     *  pj_source is something else than lat/lon. */
+    int target_srs() const override { return PROJ_SPHERE_MERC; }
+    const char *target_desc() const override { return "Spherical Mercator"; }
+};
 
-    if (Proj == PROJ_LATLONG)
-        return;
+class generic_reprojection_t : public reprojection
+{
+public:
+    generic_reprojection_t(int srs)
+    : pj_target(srs), pj_source(PROJ_LATLONG), pj_tile("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs")
+    {}
 
-    if (Proj == PROJ_SPHERE_MERC)
+    osmium::geom::Coordinates reproject(osmium::Location loc) const override
     {
-      /* The latitude co-ordinate is clipped at slightly larger than the 900913 'world'
-       * extent of +-85.0511 degrees to ensure that the points appear just outside the
-       * edge of the map. */
-
-        if (*lat > 85.07)
-            *lat = 85.07;
-        if (*lat < -85.07)
-            *lat = -85.07;
-
-        *lat = log(tan(M_PI/4.0 + (*lat) * DEG_TO_RAD / 2.0)) * EARTH_CIRCUMFERENCE/(M_PI*2);
-        *lon = (*lon) * EARTH_CIRCUMFERENCE / 360.0;
-        return;
+        using namespace osmium::geom;
+        return transform(pj_source, pj_target,
+                         Coordinates(deg_to_rad(loc.lon_without_check()),
+                                     deg_to_rad(loc.lat_without_check())));
     }
 
-    x[0] = *lon * DEG_TO_RAD;
-    y[0] = *lat * DEG_TO_RAD;
-    z[0] = 0;
+    void target_to_tile(double *lat, double *lon) const override
+    {
+        auto c = transform(pj_target, pj_tile, osmium::geom::Coordinates(*lon, *lat));
 
-    /** end of "caution" section. */
+        *lon = c.x;
+        *lat = c.y;
+    }
 
-    pj_transform(pj_source, pj_target, 1, 1, x, y, z);
+    int target_srs() const override { return PROJ_SPHERE_MERC; }
+    const char *target_desc() const override { return "Spherical Mercator"; }
 
-    *lat = y[0];
-    *lon = x[0];
-}
+private:
+    osmium::geom::CRS pj_target;
+    /** The projection of the source data. Always lat/lon (EPSG:4326). */
+    osmium::geom::CRS pj_source;
 
-/**
- * Converts from (target) coordinates to tile coordinates.
- *
- * The zoom level for the coordinates is explicitly given in the
- * variable map_width.
- */
-void reprojection::coords_to_tile(double *tilex, double *tiley, double lon, double lat,
-                                  int map_width)
-{
-    double x[1], y[1], z[1];
+    /** The projection used for tiles. Currently this is fixed to be Spherical
+     *  Mercator. You will usually have tiles in the same projection as used
+     *  for PostGIS, but it is theoretically possible to have your PostGIS data
+     *  in, say, lat/lon but still create tiles in Spherical Mercator.
+     */
+    osmium::geom::CRS pj_tile;
 
-    x[0] = lon;
-    y[0] = lat;
-    z[0] = 0;
+};
 
-    if (Proj == PROJ_LATLONG)
-    {
-        x[0] *= DEG_TO_RAD;
-        y[0] *= DEG_TO_RAD;
-    }
+} // anonymous namespace
 
-    /* since pj_tile is always spherical merc, don't bother doing anything if
-     *  destination proj is the same. */
 
-    if (Proj != PROJ_SPHERE_MERC)
+reprojection *reprojection::create_projection(int srs)
+{
+    switch (srs)
     {
-        pj_transform(pj_target, pj_tile, 1, 1, x, y, z);
-        /** FIXME: pj_transform could fail if coordinates are outside +/- 85 degrees latitude */
+        case PROJ_LATLONG: return new latlon_reprojection_t();
+        case PROJ_SPHERE_MERC: return new merc_reprojection_t();
     }
 
-    /* if ever pj_tile were allowed to be PROJ_LATLONG then results would have to
-     *  be divided by DEG_TO_RAD here. */
-
-    *tilex = map_width * (0.5 + x[0] / EARTH_CIRCUMFERENCE);
-    *tiley = map_width * (0.5 - y[0] / EARTH_CIRCUMFERENCE);
+    return new generic_reprojection_t(srs);
 }
 
-int reprojection::get_proj_id() const
+
+void reprojection::coords_to_tile(double *tilex, double *tiley,
+                                  double lon, double lat, int map_width)
 {
-	return Proj;
+    target_to_tile(&lat, &lon);
+
+    *tilex = map_width * (0.5 + lon / EARTH_CIRCUMFERENCE);
+    *tiley = map_width * (0.5 - lat / EARTH_CIRCUMFERENCE);
 }
diff --git a/reprojection.hpp b/reprojection.hpp
index 91093de..8b59ff6 100644
--- a/reprojection.hpp
+++ b/reprojection.hpp
@@ -10,44 +10,53 @@
 
 #include <boost/noncopyable.hpp>
 
-struct Projection_Info {
-    Projection_Info(const char *descr_, const char *proj4text_, int srs_, const char *option_);
+#include <osmium/geom/projection.hpp>
+#include <osmium/osm/location.hpp>
 
-    const char *descr;
-    const char *proj4text;
-    const int srs;
-    const char *option;
-};
-
-enum Projection { PROJ_LATLONG = 0, PROJ_SPHERE_MERC, PROJ_COUNT };
+enum Projection { PROJ_LATLONG = 4326, PROJ_SPHERE_MERC = 900913 };
 
-struct reprojection : public boost::noncopyable
+class reprojection : public boost::noncopyable
 {
-    explicit reprojection(int proj);
-    ~reprojection();
-
-    struct Projection_Info const* project_getprojinfo(void);
-    void reproject(double *lat, double *lon);
-    void coords_to_tile(double *tilex, double *tiley, double lon, double lat, int map_width);
-    int get_proj_id() const;
-
-private:
-    int Proj;
+public:
+    virtual ~reprojection() = default;
 
-    /** The projection of the source data. Always lat/lon (EPSG:4326). */
-    void *pj_source;
-
-    /** The target projection (used in the PostGIS tables). Controlled by the -l/-M/-m/-E options. */
-    void *pj_target;
+    /**
+     * Reproject from the source projection lat/lon (EPSG:4326)
+     * to target projection.
+     */
+    virtual osmium::geom::Coordinates reproject(osmium::Location loc) const = 0;
 
-    /** The projection used for tiles. Currently this is fixed to be Spherical
-     *  Mercator. You will usually have tiles in the same projection as used
-     *  for PostGIS, but it is theoretically possible to have your PostGIS data
-     *  in, say, lat/lon but still create tiles in Spherical Mercator.
+    /**
+     * Converts coordinates from target projection to tile projection (EPSG:3857)
+     *
+     * Do not confuse with coords_to_tile which does *not* calculate coordinates in the
+     * tile projection, but tile coordinates.
      */
-    void *pj_tile;
+    virtual void target_to_tile(double *lat, double *lon) const = 0;
 
-    struct Projection_Info *custom_projection;
+    /**
+     * Converts from target coordinates to tile coordinates.
+     *
+     * The zoom level for the coordinates is explicitly given in the
+     * variable map_width.
+     */
+    void coords_to_tile(double *tilex, double *tiley,
+                        double lon, double lat, int map_width);
+    virtual int target_srs() const = 0;
+    virtual const char *target_desc() const = 0;
+
+    bool target_latlon() const
+    {
+        return target_srs() == PROJ_LATLONG;
+    }
+
+    /**
+     * Create a reprojection object with target srs `srs`.
+     *
+     * The target projection (used in the PostGIS tables).
+     * Controlled by the -l/-m/-E options.
+     */
+    static reprojection *create_projection(int srs);
 };
 
 #endif
diff --git a/sanitizer.hpp b/sanitizer.hpp
deleted file mode 100644
index 82ad083..0000000
--- a/sanitizer.hpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef SANITIZER_H
-#define SANITIZER_H
-
-#include <libxml/xmlreader.h>
-
-xmlTextReaderPtr sanitizerOpen(const char *name);
-
-#endif
diff --git a/sprompt.cpp b/sprompt.cpp
index 63e4f21..9a4771b 100644
--- a/sprompt.cpp
+++ b/sprompt.cpp
@@ -54,13 +54,12 @@
 
 #define DEVTTY "/dev/tty"
 
-#include <stdio.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
 #include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
 
-#include <libpq-fe.h>
+#include "config.h"
 
 #ifdef HAVE_TERMIOS_H
 #include <termios.h>
@@ -73,7 +72,7 @@
 char *
 simple_prompt(const char *prompt, int maxlen, int echo)
 {
-	int			length;
+	size_t	   length;
 	char	   *destination;
 	FILE	   *termin,
 			   *termout;
@@ -152,7 +151,7 @@ simple_prompt(const char *prompt, int maxlen, int echo)
 	{
 		/* eat rest of the line */
 		char		buf[128];
-		int			buflen;
+		size_t		buflen;
 
 		do
 		{
diff --git a/style.lua b/style.lua
index c42c689..cf35391 100644
--- a/style.lua
+++ b/style.lua
@@ -1,7 +1,7 @@
 -- For documentation of Lua tag transformations, see docs/lua.md.
 
 -- Objects with any of the following keys will be treated as polygon
-polygon_keys = { 'building', 'landuse', 'amenity', 'harbour', 'historic', 'leisure', 
+polygon_keys = { 'building', 'landuse', 'amenity', 'harbour', 'historic', 'leisure',
       'man_made', 'military', 'natural', 'office', 'place', 'power',
       'public_transport', 'shop', 'sport', 'tourism', 'waterway',
       'wetland', 'water', 'aeroway' }
@@ -20,9 +20,9 @@ delete_tags = { 'FIXME', 'note', 'source' }
 -- Array used to specify z_order per key/value combination.
 -- Each element has the form {key, value, z_order, is_road}.
 -- If is_road=1, the object will be added to planet_osm_roads.
-zordering_tags = {{ 'railway', nil, 5, 1}, { 'boundary', 'administrative', 0, 1}, 
+zordering_tags = {{ 'railway', nil, 5, 1}, { 'boundary', 'administrative', 0, 1},
    { 'bridge', 'yes', 10, 0 }, { 'bridge', 'true', 10, 0 }, { 'bridge', 1, 10, 0 },
-   { 'tunnel', 'yes', -10, 0}, { 'tunnel', 'true', -10, 0}, { 'tunnel', 1, -10, 0}, 
+   { 'tunnel', 'yes', -10, 0}, { 'tunnel', 'true', -10, 0}, { 'tunnel', 1, -10, 0},
    { 'highway', 'minor', 3, 0}, { 'highway', 'road', 3, 0 }, { 'highway', 'unclassified', 3, 0 },
    { 'highway', 'residential', 3, 0 }, { 'highway', 'tertiary_link', 4, 0}, { 'highway', 'tertiary', 4, 0},
    { 'highway', 'secondary_link', 6, 1}, { 'highway', 'secondary', 6, 1},
@@ -72,7 +72,7 @@ function filter_tags_generic(keyvalues, numberofkeys)
    for i,k in ipairs(delete_tags) do
       keyvalues[k] = nil
    end
-   
+
    -- Filter out objects that do not have any of the keys in generic_keys
    tagcount = 0
    for k,v in pairs(keyvalues) do
@@ -126,7 +126,7 @@ function filter_tags_way (keyvalues, numberofkeys)
          break
       end
    end
-   
+
    -- Treat objects tagged as area=yes, area=1, or area=true as polygon,
    -- and treat objects tagged as area=no, area=0, or area=false not as polygon
    if ((keyvalues["area"] == "yes") or (keyvalues["area"] == "1") or (keyvalues["area"] == "true")) then
@@ -155,7 +155,7 @@ function filter_tags_relation_member (keyvalues, keyvaluemembers, roles, memberc
 
    -- Remove type key
    keyvalues["type"] = nil
-  
+
    -- Relations with type=boundary are treated as linestring
    if (type == "boundary") then
       linestring = 1
diff --git a/table.cpp b/table.cpp
index 94fd383..1c21cb9 100644
--- a/table.cpp
+++ b/table.cpp
@@ -18,7 +18,7 @@ typedef boost::format fmt;
 table_t::table_t(const string& conninfo, const string& name, const string& type, const columns_t& columns, const hstores_t& hstore_columns,
     const int srid, const bool append, const bool slim, const bool drop_temp, const int hstore_mode,
     const bool enable_hstore_index, const boost::optional<string>& table_space, const boost::optional<string>& table_space_index) :
-    conninfo(conninfo), name(name), type(type), sql_conn(NULL), copyMode(false), srid((fmt("%1%") % srid).str()),
+    conninfo(conninfo), name(name), type(type), sql_conn(nullptr), copyMode(false), srid((fmt("%1%") % srid).str()),
     append(append), slim(slim), drop_temp(drop_temp), hstore_mode(hstore_mode), enable_hstore_index(enable_hstore_index),
     columns(columns), hstore_columns(hstore_columns), table_space(table_space), table_space_index(table_space_index)
 {
@@ -36,7 +36,7 @@ table_t::table_t(const string& conninfo, const string& name, const string& type,
 }
 
 table_t::table_t(const table_t& other):
-    conninfo(other.conninfo), name(other.name), type(other.type), sql_conn(NULL), copyMode(false), buffer(), srid(other.srid),
+    conninfo(other.conninfo), name(other.name), type(other.type), sql_conn(nullptr), copyMode(false), buffer(), srid(other.srid),
     append(other.append), slim(other.slim), drop_temp(other.drop_temp), hstore_mode(other.hstore_mode), enable_hstore_index(other.enable_hstore_index),
     columns(other.columns), hstore_columns(other.hstore_columns), copystr(other.copystr), table_space(other.table_space),
     table_space_index(other.table_space_index), single_fmt(other.single_fmt), point_fmt(other.point_fmt), del_fmt(other.del_fmt)
@@ -47,7 +47,7 @@ table_t::table_t(const table_t& other):
     if (other.sql_conn) {
         connect();
         //let postgres cache this query as it will presumably happen a lot
-        pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("PREPARE get_wkt (" POSTGRES_OSMID_TYPE ") AS SELECT ST_AsText(way) FROM %1% WHERE osm_id = $1") % name).str());
+        pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("PREPARE get_wkb (" POSTGRES_OSMID_TYPE ") AS SELECT way FROM %1% WHERE osm_id = $1") % name).str());
         //start the copy
         begin();
         pgsql_exec_simple(sql_conn, PGRES_COPY_IN, copystr);
@@ -66,10 +66,10 @@ std::string const& table_t::get_name() {
 
 void table_t::teardown()
 {
-    if(sql_conn != NULL)
+    if(sql_conn != nullptr)
     {
         PQfinish(sql_conn);
-        sql_conn = NULL;
+        sql_conn = nullptr;
     }
 }
 
@@ -108,15 +108,6 @@ void table_t::start()
     if (!append)
     {
         pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("DROP TABLE IF EXISTS %1%") % name).str());
-    }//we are checking in append mode that the srid you specified matches whats already there
-    else
-    {
-        boost::shared_ptr<PGresult> res =  pgsql_exec_simple(sql_conn, PGRES_TUPLES_OK, (fmt("SELECT srid FROM geometry_columns WHERE f_table_name='%1%';") % name).str());
-        if (!((PQntuples(res.get()) == 1) && (PQnfields(res.get()) == 1)))
-            throw std::runtime_error((fmt("Problem reading geometry information for table %1% - does it exist?\n") % name).str());
-        char* their_srid = PQgetvalue(res.get(), 0, 0);
-        if (srid.compare(their_srid) != 0)
-            throw std::runtime_error((fmt("SRID mismatch: cannot append to table %1% (SRID %2%) using selected SRID %3%\n") % name % their_srid % srid).str());
     }
 
     /* These _tmp tables can be left behind if we run out of disk space */
@@ -146,6 +137,10 @@ void table_t::start()
         else
             sql[sql.length() - 1] = ')';
 
+        // The final tables are created with CREATE TABLE AS ... SELECT * FROM ...
+        // This means that they won't get this autovacuum setting, so it doesn't
+        // doesn't need to be RESET on these tables
+        sql += " WITH ( autovacuum_enabled = FALSE )";
         //add the main table space
         if (table_space)
             sql += " TABLESPACE " + table_space.get();
@@ -159,7 +154,7 @@ void table_t::start()
 
         //slim mode needs this to be able to apply diffs
         if (slim && !drop_temp) {
-            sql = (fmt("CREATE INDEX %1%_pkey ON %2% USING BTREE (osm_id)") % name % name).str();
+            sql = (fmt("CREATE INDEX %1%_pkey ON %1% USING BTREE (osm_id)") % name).str();
             if (table_space_index)
                 sql += " TABLESPACE " + table_space_index.get();
             pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, sql);
@@ -168,13 +163,13 @@ void table_t::start()
     }//appending
     else {
         //check the columns against those in the existing table
-        boost::shared_ptr<PGresult> res = pgsql_exec_simple(sql_conn, PGRES_TUPLES_OK, (fmt("SELECT * FROM %1% LIMIT 0") % name).str());
+        std::shared_ptr<PGresult> res = pgsql_exec_simple(sql_conn, PGRES_TUPLES_OK, (fmt("SELECT * FROM %1% LIMIT 0") % name).str());
         for(columns_t::const_iterator column = columns.begin(); column != columns.end(); ++column)
         {
             if(PQfnumber(res.get(), ('"' + column->first + '"').c_str()) < 0)
             {
 #if 0
-                throw std::runtime_error((fmt("Append failed. Column \"%1%\" is missing from \"%2%\"\n") % info.name % name).str());
+                throw std::runtime_error((fmt("Append failed. Column \"%1%\" is missing from \"%1%\"\n") % info.name).str());
 #else
                 fprintf(stderr, "%s", (fmt("Adding new column \"%1%\" to \"%2%\"\n") % column->first % name).str().c_str());
                 pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("ALTER TABLE %1% ADD COLUMN \"%2%\" %3%") % name % column->first % column->second).str());
@@ -189,7 +184,7 @@ void table_t::start()
     }
 
     //let postgres cache this query as it will presumably happen a lot
-    pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("PREPARE get_wkt (" POSTGRES_OSMID_TYPE ") AS SELECT ST_AsText(way) FROM %1% WHERE osm_id = $1") % name).str());
+    pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("PREPARE get_wkb (" POSTGRES_OSMID_TYPE ") AS SELECT way FROM %1% WHERE osm_id = $1") % name).str());
 
     //generate column list for COPY
     string cols = "osm_id,";
@@ -226,43 +221,43 @@ void table_t::stop()
 
         // Special handling for empty geometries because geohash chokes on
         // empty geometries on postgis 1.5.
-        pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("CREATE TABLE %1%_tmp %2% AS SELECT * FROM %3% ORDER BY CASE WHEN ST_IsEmpty(way) THEN NULL ELSE ST_GeoHash(ST_Transform(ST_Envelope(way),4326),10) END") % name % (table_space ? "TABLESPACE " + table_space.get() : "") % name).str());
+        pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("CREATE TABLE %1%_tmp %2% AS SELECT * FROM %1% ORDER BY CASE WHEN ST_IsEmpty(way) THEN NULL ELSE ST_GeoHash(ST_Transform(ST_Envelope(way),4326),10) END") % name % (table_space ? "TABLESPACE " + table_space.get() : "")).str());
         pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("DROP TABLE %1%") % name).str());
-        pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("ALTER TABLE %1%_tmp RENAME TO %2%") % name % name).str());
+        pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("ALTER TABLE %1%_tmp RENAME TO %1%") % name).str());
         // Re-add constraints if on 1.x. 2.0 has typemod, and they automatically come with CREATE TABLE AS
         pgsql_exec_simple(sql_conn, PGRES_TUPLES_OK, (fmt("SELECT CASE WHEN PostGIS_Lib_Version() LIKE '1.%%' THEN Populate_Geometry_Columns('%1%'::regclass) ELSE 1 END;") % name).str());
         fprintf(stderr, "Copying %s to cluster by geometry finished\n", name.c_str());
-        fprintf(stderr, "Creating geometry index on  %s\n", name.c_str());
+        fprintf(stderr, "Creating geometry index on %s\n", name.c_str());
 
         // Use fillfactor 100 for un-updatable imports
-        pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("CREATE INDEX %1%_index ON %2% USING GIST (way) %3% %4%") % name % name %
+        pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("CREATE INDEX %1%_index ON %1% USING GIST (way) %2% %3%") % name %
             (slim && !drop_temp ? "" : "WITH (FILLFACTOR=100)") %
             (table_space_index ? "TABLESPACE " + table_space_index.get() : "")).str());
 
         /* slim mode needs this to be able to apply diffs */
         if (slim && !drop_temp)
         {
-            fprintf(stderr, "Creating osm_id index on  %s\n", name.c_str());
-            pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("CREATE INDEX %1%_pkey ON %2% USING BTREE (osm_id) %3%") % name % name %
+            fprintf(stderr, "Creating osm_id index on %s\n", name.c_str());
+            pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("CREATE INDEX %1%_pkey ON %1% USING BTREE (osm_id) %2%") % name %
                 (table_space_index ? "TABLESPACE " + table_space_index.get() : "")).str());
         }
         /* Create hstore index if selected */
         if (enable_hstore_index) {
-            fprintf(stderr, "Creating hstore indexes on  %s\n", name.c_str());
+            fprintf(stderr, "Creating hstore indexes on %s\n", name.c_str());
             if (hstore_mode != HSTORE_NONE) {
-                pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("CREATE INDEX %1%_tags_index ON %2% USING GIN (tags) %3%") % name % name %
+                pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("CREATE INDEX %1%_tags_index ON %1% USING GIN (tags) %2%") % name %
                     (table_space_index ? "TABLESPACE " + table_space_index.get() : "")).str());
             }
             for(size_t i = 0; i < hstore_columns.size(); ++i) {
-                pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("CREATE INDEX %1%_hstore_%2%_index ON %3% USING GIN (\"%4%\") %5%") % name % i % name % hstore_columns[i] %
+                pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("CREATE INDEX %1%_hstore_%2%_index ON %1% USING GIN (\"%3%\") %4%") % name % i % hstore_columns[i] %
                     (table_space_index ? "TABLESPACE " + table_space_index.get() : "")).str());
             }
         }
-        fprintf(stderr, "Creating indexes on  %s finished\n", name.c_str());
+        fprintf(stderr, "Creating indexes on %s finished\n", name.c_str());
         pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("GRANT SELECT ON %1% TO PUBLIC") % name).str());
         pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (fmt("ANALYZE %1%") % name).str());
         time(&end);
-        fprintf(stderr, "All indexes on  %s created  in %ds\n", name.c_str(), (int)(end - start));
+        fprintf(stderr, "All indexes on %s created in %ds\n", name.c_str(), (int)(end - start));
     }
     teardown();
 
@@ -285,7 +280,7 @@ void table_t::stop_copy()
     };
 
     //stop the copy
-    stop = PQputCopyEnd(sql_conn, NULL);
+    stop = PQputCopyEnd(sql_conn, nullptr);
     if (stop != 1)
        throw std::runtime_error((fmt("stop COPY_END for %1% failed: %2%\n") % name % PQerrorMessage(sql_conn)).str());
 
@@ -302,7 +297,7 @@ void table_t::stop_copy()
 
 void table_t::write_node(const osmid_t id, const taglist_t &tags, double lat, double lon)
 {
-    write_wkt(id, tags, (point_fmt % lon % lat).str().c_str());
+    write_row(id, tags, (point_fmt % lon % lat).str());
 }
 
 void table_t::delete_row(const osmid_t id)
@@ -311,7 +306,7 @@ void table_t::delete_row(const osmid_t id)
     pgsql_exec_simple(sql_conn, PGRES_COMMAND_OK, (del_fmt % name % id).str());
 }
 
-void table_t::write_wkt(const osmid_t id, const taglist_t &tags, const char *wkt)
+void table_t::write_row(const osmid_t id, const taglist_t &tags, const std::string &geom)
 {
     //add the osm id
     buffer.append((single_fmt % id).str());
@@ -324,7 +319,7 @@ void table_t::write_wkt(const osmid_t id, const taglist_t &tags, const char *wkt
         used.assign(tags.size(), false);
 
     //get the regular columns' values
-    write_columns(tags, buffer, hstore_mode == HSTORE_NORM?&used:NULL);
+    write_columns(tags, buffer, hstore_mode == HSTORE_NORM?&used:nullptr);
 
     //get the hstore columns' values
     write_hstore_columns(tags, buffer);
@@ -333,12 +328,12 @@ void table_t::write_wkt(const osmid_t id, const taglist_t &tags, const char *wkt
     if (hstore_mode != HSTORE_NONE)
         write_tags_column(tags, buffer, used);
 
-    //give the wkt an srid
+    //give the geometry an srid
     buffer.append("SRID=");
     buffer.append(srid);
     buffer.push_back(';');
-    //add the wkt
-    buffer.append(wkt);
+    //add the geometry
+    buffer.append(geom);
     //we need \n because we are copying from stdin
     buffer.push_back('\n');
 
@@ -383,7 +378,7 @@ void table_t::write_tags_column(const taglist_t &tags, std::string& values,
     bool added = false;
     for (size_t i = 0; i < tags.size(); ++i)
     {
-        const tag& xtag = tags[i];
+        const tag_t& xtag = tags[i];
         //skip z_order tag and keys which have their own column
         if (used[i] || ("z_order" == xtag.key))
             continue;
@@ -433,7 +428,7 @@ void table_t::write_hstore_columns(const taglist_t &tags, std::string& values)
             }
         }
 
-        //if you found not matching tags write a NULL
+        //if you found not matching tags write a NUL
         if(!added)
             values.append("\\N");
 
@@ -521,9 +516,9 @@ void table_t::escape_type(const string &value, const string &type, string& dst)
         escape(value, dst);
 }
 
-boost::shared_ptr<table_t::wkt_reader> table_t::get_wkt_reader(const osmid_t id)
+table_t::wkb_reader table_t::get_wkb_reader(const osmid_t id)
 {
-    //cant get wkt using the prepared statement without stopping the copy first
+    //cant get wkb using the prepared statement without stopping the copy first
     stop_copy();
 
     char const *paramValues[1];
@@ -531,36 +526,8 @@ boost::shared_ptr<table_t::wkt_reader> table_t::get_wkt_reader(const osmid_t id)
     snprintf(tmp, sizeof(tmp), "%" PRIdOSMID, id);
     paramValues[0] = tmp;
 
-    //the prepared statement get_wkt will behave differently depending on the sql_conn
+    //the prepared statement get_wkb will behave differently depending on the sql_conn
     //each table has its own sql_connection with the get_way referring to the appropriate table
-    PGresult* res = pgsql_execPrepared(sql_conn, "get_wkt", 1, (const char * const *)paramValues, PGRES_TUPLES_OK);
-    return boost::shared_ptr<wkt_reader>(new wkt_reader(res));
-}
-
-table_t::wkt_reader::wkt_reader(PGresult* result):result(result), current(0)
-{
-    count = PQntuples(result);
-}
-
-table_t::wkt_reader::~wkt_reader()
-{
-    PQclear(result);
-}
-
-const char* table_t::wkt_reader::get_next()
-{
-    if(current < count)
-        return PQgetvalue(result, current++, 0);
-    return NULL;
-}
-
-size_t table_t::wkt_reader::get_count() const
-{
-    return count;
-}
-
-void table_t::wkt_reader::reset()
-{
-    //NOTE: PQgetvalue doc doesn't say if you can call it multiple times with the same row col
-    current = 0;
+    PGresult* res = pgsql_execPrepared(sql_conn, "get_wkb", 1, (const char * const *)paramValues, PGRES_TUPLES_OK);
+    return wkb_reader(res);
 }
diff --git a/table.hpp b/table.hpp
index 91e41ce..9bd2bb2 100644
--- a/table.hpp
+++ b/table.hpp
@@ -8,10 +8,10 @@
 #include <string>
 #include <vector>
 #include <utility>
+#include <memory>
 
 #include <boost/optional.hpp>
 #include <boost/format.hpp>
-#include <boost/shared_ptr.hpp>
 
 typedef std::vector<std::string> hstores_t;
 typedef std::vector<std::pair<std::string, std::string> > columns_t;
@@ -31,28 +31,51 @@ class table_t
         void begin();
         void commit();
 
-        void write_wkt(const osmid_t id, const taglist_t &tags, const char *wkt);
+        void write_row(const osmid_t id, const taglist_t &tags, const std::string &geom);
         void write_node(const osmid_t id, const taglist_t &tags, double lat, double lon);
         void delete_row(const osmid_t id);
 
         std::string const& get_name();
 
-        //interface from retrieving well known text geometry from the table
-        struct wkt_reader
+        struct pg_result_closer
         {
-            friend class table_t;
+            void operator() (PGresult* result)
+            {
+                PQclear(result);
+            }
+
+        };
+
+        //interface from retrieving well known binary geometry from the table
+        class wkb_reader
+        {
+            friend table_t;
             public:
-                virtual ~wkt_reader();
-                const char* get_next();
-                size_t get_count() const;
-                void reset();
+                const char* get_next()
+                {
+                    if (m_current < m_count) {
+                        return PQgetvalue(m_result.get(), m_current++, 0);
+                    }
+                    return nullptr;
+                }
+
+                int get_count() const { return m_count; }
+                void reset()
+                {
+                    //NOTE: PQgetvalue doc doesn't say if you can call it
+                    //      multiple times with the same row col
+                    m_current = 0;
+                }
             private:
-                wkt_reader(PGresult* result);
-                PGresult* result;
-                size_t count;
-                size_t current;
+                wkb_reader(PGresult* result)
+                : m_result(result), m_count(PQntuples(result)), m_current(0)
+                {}
+
+                std::unique_ptr<PGresult, pg_result_closer> m_result;
+                int m_count;
+                int m_current;
         };
-        boost::shared_ptr<wkt_reader> get_wkt_reader(const osmid_t id);
+        wkb_reader get_wkb_reader(const osmid_t id);
 
     protected:
         void connect();
diff --git a/taginfo.cpp b/taginfo.cpp
index a00141a..329a818 100644
--- a/taginfo.cpp
+++ b/taginfo.cpp
@@ -33,7 +33,8 @@ static const flagsname tagflags[] = {
     flagsname("linear",  FLAG_LINEAR),
     flagsname("nocache", FLAG_NOCACHE),
     flagsname("delete",  FLAG_DELETE),
-    flagsname("phstore", FLAG_PHSTORE)
+    flagsname("phstore", FLAG_PHSTORE),
+    flagsname("nocolumn", FLAG_NOCOLUMN)
 };
 #define NUM_FLAGS ((signed)(sizeof(tagflags) / sizeof(tagflags[0])))
 
@@ -83,7 +84,7 @@ columns_t export_list::normal_columns(enum OsmType id) const {
     {
         if( info->flags & FLAG_DELETE )
             continue;
-        if( (info->flags & FLAG_PHSTORE ) == FLAG_PHSTORE)
+        if( (info->flags & FLAG_NOCOLUMN ) == FLAG_NOCOLUMN)
             continue;
         columns.push_back(std::pair<std::string, std::string>(info->name, info->type));
     }
@@ -92,7 +93,7 @@ columns_t export_list::normal_columns(enum OsmType id) const {
 
 int parse_tag_flags(const char *flags_, int lineno) {
     int temp_flags = 0;
-    char *str = NULL, *saveptr = NULL;
+    char *str = nullptr, *saveptr = nullptr;
     int i = 0;
 
     // yuck! but strtok requires a non-const char * pointer, and i'm fairly sure it
@@ -100,7 +101,7 @@ int parse_tag_flags(const char *flags_, int lineno) {
     char *flags = const_cast<char *>(flags_);
 
     //split the flags column on commas and keep track of which flags you've seen in a bit mask
-    for(str = strtok_r(flags, ",\r\n", &saveptr); str != NULL; str = strtok_r(NULL, ",\r\n", &saveptr))
+    for(str = strtok_r(flags, ",\r\n", &saveptr); str != nullptr; str = strtok_r(nullptr, ",\r\n", &saveptr))
     {
       for( i=0; i<NUM_FLAGS; i++ )
       {
@@ -140,7 +141,7 @@ int read_style_file( const std::string &filename, export_list *exlist )
   }
 
   //for each line of the style file
-  while( fgets( buffer, sizeof(buffer), in) != NULL )
+  while( fgets( buffer, sizeof(buffer), in) != nullptr )
   {
     lineno++;
 
diff --git a/taginfo_impl.hpp b/taginfo_impl.hpp
index 5910fac..d778be7 100644
--- a/taginfo_impl.hpp
+++ b/taginfo_impl.hpp
@@ -11,7 +11,8 @@
 #define FLAG_LINEAR  2    /* For lines table */
 #define FLAG_NOCACHE 4    /* Optimisation: don't bother remembering this one */
 #define FLAG_DELETE  8    /* These tags should be simply deleted on sight */
-#define FLAG_PHSTORE 17   /* polygons without own column but listed in hstore this implies FLAG_POLYGON */
+#define FLAG_NOCOLUMN 16    /* objects without column but should be listed in database hstore column */
+#define FLAG_PHSTORE 17   /* same as FLAG_NOCOLUMN & FLAG_POLYGON to maintain compatibility */
 
 struct taginfo {
     taginfo();
diff --git a/tagtransform.cpp b/tagtransform.cpp
index dd7d9fc..800f03a 100644
--- a/tagtransform.cpp
+++ b/tagtransform.cpp
@@ -98,7 +98,7 @@ void add_z_order(taglist_t &tags, int *roads)
 
     char z[13];
     snprintf(z, sizeof(z), "%d", z_order);
-    tags.push_back(tag("z_order", z));
+    tags.push_back(tag_t("z_order", z));
 }
 
 unsigned int c_filter_rel_member_tags(const taglist_t &rel_tags,
@@ -125,20 +125,20 @@ unsigned int c_filter_rel_member_tags(const taglist_t &rel_tags,
     }
 
     /* Clone tags from relation */
-    for (taglist_t::const_iterator it = rel_tags.begin(); it != rel_tags.end(); ++it) {
+    for (const auto& rel_tag: rel_tags) {
         //copy the name tag as "route_name"
-        if (is_route && (it->key == "name"))
-            out_tags.push_dedupe(tag("route_name", it->value));
+        if (is_route && (rel_tag.key == "name"))
+            out_tags.push_dedupe(tag_t("route_name", rel_tag.value));
         //copy all other tags except for "type"
-        if (it->key != "type")
-            out_tags.push_dedupe(*it);
+        if (rel_tag.key != "type")
+            out_tags.push_dedupe(rel_tag);
     }
 
     if (is_route) {
         const std::string *netw = rel_tags.get("network");
         int networknr = -1;
 
-        if (netw != NULL) {
+        if (netw != nullptr) {
             const std::string *state = rel_tags.get("state");
             std::string statetype("yes");
             if (state) {
@@ -149,22 +149,22 @@ unsigned int c_filter_rel_member_tags(const taglist_t &rel_tags,
             }
             if (*netw == "lcn") {
                 networknr = 10;
-                out_tags.push_dedupe(tag("lcn", statetype));
+                out_tags.push_dedupe(tag_t("lcn", statetype));
             } else if (*netw == "rcn") {
                 networknr = 11;
-                out_tags.push_dedupe(tag("rcn", statetype));
+                out_tags.push_dedupe(tag_t("rcn", statetype));
             } else if (*netw == "ncn") {
                 networknr = 12;
-                out_tags.push_dedupe(tag("ncn", statetype));
+                out_tags.push_dedupe(tag_t("ncn", statetype));
             } else if (*netw == "lwn") {
                 networknr = 20;
-                out_tags.push_dedupe(tag("lwn", statetype));
+                out_tags.push_dedupe(tag_t("lwn", statetype));
             } else if (*netw == "rwn") {
                 networknr = 21;
-                out_tags.push_dedupe(tag("rwn", statetype));
+                out_tags.push_dedupe(tag_t("rwn", statetype));
             } else if (*netw == "nwn") {
                 networknr = 22;
-                out_tags.push_dedupe(tag("nwn", statetype));
+                out_tags.push_dedupe(tag_t("nwn", statetype));
             }
         }
 
@@ -173,28 +173,28 @@ unsigned int c_filter_rel_member_tags(const taglist_t &rel_tags,
             if ((*prefcol)[0] == '0' || (*prefcol)[0] == '1'
                     || (*prefcol)[0] == '2' || (*prefcol)[0] == '3'
                     || (*prefcol)[0] == '4') {
-                out_tags.push_dedupe(tag("route_pref_color", *prefcol));
+                out_tags.push_dedupe(tag_t("route_pref_color", *prefcol));
             } else {
-                out_tags.push_dedupe(tag("route_pref_color", "0"));
+                out_tags.push_dedupe(tag_t("route_pref_color", "0"));
             }
         } else {
-            out_tags.push_dedupe(tag("route_pref_color", "0"));
+            out_tags.push_dedupe(tag_t("route_pref_color", "0"));
         }
 
         const std::string *relref = rel_tags.get("ref");
         if (relref != NULL ) {
             if (networknr == 10) {
-                out_tags.push_dedupe(tag("lcn_ref", *relref));
+                out_tags.push_dedupe(tag_t("lcn_ref", *relref));
             } else if (networknr == 11) {
-                out_tags.push_dedupe(tag("rcn_ref", *relref));
+                out_tags.push_dedupe(tag_t("rcn_ref", *relref));
             } else if (networknr == 12) {
-                out_tags.push_dedupe(tag("ncn_ref", *relref));
+                out_tags.push_dedupe(tag_t("ncn_ref", *relref));
             } else if (networknr == 20) {
-                out_tags.push_dedupe(tag("lwn_ref", *relref));
+                out_tags.push_dedupe(tag_t("lwn_ref", *relref));
             } else if (networknr == 21) {
-                out_tags.push_dedupe(tag("rwn_ref", *relref));
+                out_tags.push_dedupe(tag_t("rwn_ref", *relref));
             } else if (networknr == 22) {
-                out_tags.push_dedupe(tag("nwn_ref", *relref));
+                out_tags.push_dedupe(tag_t("nwn_ref", *relref));
             }
         }
     } else if (is_boundary) {
@@ -212,16 +212,15 @@ unsigned int c_filter_rel_member_tags(const taglist_t &rel_tags,
         /* Collect a list of polygon-like tags, these are used later to
          identify if an inner rings looks like it should be rendered separately */
         taglist_t poly_tags;
-        for (taglist_t::const_iterator it = out_tags.begin(); it != out_tags.end(); ++it) {
-            if (it->key == "area") {
-                poly_tags.push_back(*it);
+        for (const auto& tag: out_tags) {
+            if (tag.key == "area") {
+                poly_tags.push_back(tag);
             } else {
                 const std::vector<taginfo> &infos = exlist.get(OSMTYPE_WAY);
-                for (std::vector<taginfo>::const_iterator info = infos.begin();
-                     info != infos.end(); ++info) {
-                    if (info->name == it->key) {
-                        if (info->flags & FLAG_POLYGON) {
-                            poly_tags.push_back(*it);
+                for (const auto& info: infos) {
+                    if (info.name == tag.key) {
+                        if (info.flags & FLAG_POLYGON) {
+                            poly_tags.push_back(tag);
                         }
                         break;
                     }
@@ -239,9 +238,9 @@ unsigned int c_filter_rel_member_tags(const taglist_t &rel_tags,
 
                 /* insert all tags of the first outerway to the potential list of copied tags. */
                 if (first_outerway) {
-                    for (taglist_t::const_iterator it = member_tags[i].begin();
-                         it != member_tags[i].end(); ++it)
-                        poly_tags.push_back(*it);
+                    for (const auto& tag: member_tags[i]) {
+                        poly_tags.push_back(tag);
+                    }
                 } else {
                     /* Check if all of the tags in the list of potential tags are present on this way,
                        otherwise remove from the list of potential tags. Tags need to be present on
@@ -258,8 +257,9 @@ unsigned int c_filter_rel_member_tags(const taglist_t &rel_tags,
                 first_outerway = 0;
             }
             /* Copy the list identified outer way tags over to the relation */
-            for (taglist_t::const_iterator it = poly_tags.begin(); it != poly_tags.end(); ++it)
-                out_tags.push_dedupe(*it);
+            for (const auto& poly_tag: poly_tags) {
+                out_tags.push_dedupe(poly_tag);
+            }
 
             /* We need to re-check and only keep polygon tags in the list of polytags */
             // TODO what is that for? The list is cleared just below.
@@ -299,14 +299,13 @@ unsigned int c_filter_rel_member_tags(const taglist_t &rel_tags,
     if (make_polygon) {
         for (size_t i = 0; i < member_tags.size(); i++) {
             member_superseeded[i] = 1;
-            for (taglist_t::const_iterator p = member_tags[i].begin();
-                 p != member_tags[i].end(); ++p) {
-                const std::string *v = out_tags.get(p->key);
-                if (!v || *v != p->value) {
+            for (const auto& member_tag: member_tags[i]) {
+                const std::string *v = out_tags.get(member_tag.key);
+                if (!v || *v != member_tag.value) {
                     /* z_order and osm_ are automatically generated tags, so ignore them */
-                    if ((p->key != "z_order") && (p->key != "osm_user") &&
-                        (p->key != "osm_version") && (p->key != "osm_uid") &&
-                        (p->key != "osm_changeset") && (p->key != "osm_timestamp")) {
+                    if ((member_tag.key != "z_order") && (member_tag.key != "osm_user") &&
+                        (member_tag.key != "osm_version") && (member_tag.key != "osm_uid") &&
+                        (member_tag.key != "osm_changeset") && (member_tag.key != "osm_timestamp")) {
                         member_superseeded[i] = 0;
                         break;
                     }
@@ -323,7 +322,7 @@ unsigned int c_filter_rel_member_tags(const taglist_t &rel_tags,
 
 #ifdef HAVE_LUA
 unsigned tagtransform::lua_filter_rel_member_tags(const taglist_t &rel_tags,
-        const multitaglist_t &member_tags, const rolelist_t &member_roles,
+        const multitaglist_t &members_tags, const rolelist_t &member_roles,
         int *member_superseeded, int *make_boundary, int *make_polygon, int *roads,
         taglist_t &out_tags)
 {
@@ -331,22 +330,21 @@ unsigned tagtransform::lua_filter_rel_member_tags(const taglist_t &rel_tags,
 
     lua_newtable(L);    /* relations key value table */
 
-    for (taglist_t::const_iterator it = rel_tags.begin(); it != rel_tags.end(); ++it) {
-        lua_pushstring(L, it->key.c_str());
-        lua_pushstring(L, it->value.c_str());
+    for (const auto& rel_tag: rel_tags) {
+        lua_pushstring(L, rel_tag.key.c_str());
+        lua_pushstring(L, rel_tag.value.c_str());
         lua_rawset(L, -3);
     }
 
     lua_newtable(L);    /* member tags table */
 
     int idx = 1;
-    for (multitaglist_t::const_iterator list = member_tags.begin();
-         list != member_tags.end(); ++list) {
+    for (const auto& member_tags: members_tags) {
         lua_pushnumber(L, idx++);
         lua_newtable(L);    /* member key value table */
-        for (taglist_t::const_iterator it = list->begin(); it != list->end(); ++it) {
-            lua_pushstring(L, it->key.c_str());
-            lua_pushstring(L, it->value.c_str());
+        for (const auto& member_tag: member_tags) {
+            lua_pushstring(L, member_tag.key.c_str());
+            lua_pushstring(L, member_tag.value.c_str());
             lua_rawset(L, -3);
         }
         lua_rawset(L, -3);
@@ -376,7 +374,7 @@ unsigned tagtransform::lua_filter_rel_member_tags(const taglist_t &rel_tags,
     lua_pop(L,1);
 
     lua_pushnil(L);
-    for (size_t i = 0; i < member_tags.size(); i++) {
+    for (size_t i = 0; i < members_tags.size(); i++) {
         if (lua_next(L,-2)) {
             member_superseeded[i] = lua_tointeger(L,-1);
             lua_pop(L,1);
@@ -390,7 +388,7 @@ unsigned tagtransform::lua_filter_rel_member_tags(const taglist_t &rel_tags,
     while (lua_next(L,-2) != 0) {
         const char *key = lua_tostring(L,-2);
         const char *value = lua_tostring(L,-1);
-        out_tags.push_back(tag(key, value));
+        out_tags.push_back(tag_t(key, value));
         lua_pop(L,1);
     }
     lua_pop(L,1);
@@ -423,29 +421,30 @@ tagtransform::tagtransform(const options_t *options_)
     , m_rel_mem_func(options->tag_transform_rel_mem_func.get_value_or("filter_tags_relation_member"))
 #endif /* HAVE_LUA */
 {
-	if (transform_method) {
-                fprintf(stderr, "Using lua based tag processing pipeline with script %s\n", options->tag_transform_script->c_str());
+    if (transform_method) {
+        fprintf(stderr, "Using lua based tag processing pipeline with script %s\n", options->tag_transform_script->c_str());
 #ifdef HAVE_LUA
-		L = luaL_newstate();
-		luaL_openlibs(L);
-		luaL_dofile(L, options->tag_transform_script->c_str());
+        L = luaL_newstate();
+        luaL_openlibs(L);
+        luaL_dofile(L, options->tag_transform_script->c_str());
 
         check_lua_function_exists(m_node_func);
         check_lua_function_exists(m_way_func);
         check_lua_function_exists(m_rel_func);
         check_lua_function_exists(m_rel_mem_func);
 #else
-		throw std::runtime_error("Error: Could not init lua tag transform, as lua support was not compiled into this version");
+        throw std::runtime_error("Error: Could not init lua tag transform, as lua support was not compiled into this version");
 #endif
-	} else {
-		fprintf(stderr, "Using built-in tag processing pipeline\n");
-	}
+    } else {
+        fprintf(stderr, "Using built-in tag processing pipeline\n");
+    }
 }
 
 tagtransform::~tagtransform() {
 #ifdef HAVE_LUA
-	if (transform_method)
-    lua_close(L);
+    if (transform_method) {
+        lua_close(L);
+    }
 #endif
 }
 
@@ -546,7 +545,7 @@ unsigned tagtransform::lua_filter_basic_tags(OsmType type, const taglist_t &tags
     while (lua_next(L,-2) != 0) {
         const char *key = lua_tostring(L,-2);
         const char *value = lua_tostring(L,-1);
-        out_tags.push_back(tag(key, value));
+        out_tags.push_back(tag_t(key, value));
         lua_pop(L,1);
     }
 
@@ -652,14 +651,14 @@ unsigned int tagtransform::c_filter_basic_tags(OsmType type, const taglist_t &ta
                         break;
                     }
                 }
-            } 
+            }
         }
     }
 
     if (polygon) {
         if (add_area_tag) {
             /* If we need to force this as a polygon, append an area tag */
-            out_tags.push_dedupe(tag("area", "yes"));
+            out_tags.push_dedupe(tag_t("area", "yes"));
             *polygon = 1;
         } else {
             *polygon = tags.get_bool("area", flags & FLAG_POLYGON);
diff --git a/tagtransform.hpp b/tagtransform.hpp
index 00547ac..cbce2ca 100644
--- a/tagtransform.hpp
+++ b/tagtransform.hpp
@@ -41,7 +41,7 @@ private:
                                  int *roads, const export_list &exlist,
                                  taglist_t &out_tags, bool strict);
     unsigned int lua_filter_rel_member_tags(const taglist_t &rel_tags,
-        const multitaglist_t &member_tags, const rolelist_t &member_roles,
+        const multitaglist_t &members_tags, const rolelist_t &member_roles,
         int *member_superseeded, int *make_boundary, int *make_polygon, int *roads,
         taglist_t &out_tags);
     void check_lua_function_exists(const std::string &func_name);
diff --git a/tests/008-ch.osc.gz b/tests/008-ch.osc.gz
new file mode 100644
index 0000000..c0f6be2
Binary files /dev/null and b/tests/008-ch.osc.gz differ
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 0000000..2e27e22
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,69 @@
+add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} ${ARGS})
+add_dependencies(check osm2pgsql)
+
+add_library(common-pg STATIC common-pg.cpp common-pg.hpp common-cleanup.cpp common-cleanup.hpp)
+add_library(middle-tests STATIC middle-tests.cpp middle-tests.hpp)
+
+set(TESTS
+  test-expire-tiles.cpp
+  test-hstore-match-only.cpp
+  test-middle-flat.cpp
+  test-middle-pgsql.cpp
+  test-middle-ram.cpp
+  test-options-database.cpp
+  test-options-parse.cpp
+  test-output-multi-line-storage.cpp
+  test-output-multi-line.cpp
+  test-output-multi-point-multi-table.cpp
+  test-output-multi-point.cpp
+  test-output-multi-poly-trivial.cpp
+  test-output-multi-polygon.cpp
+  test-output-multi-tags.cpp
+  test-output-pgsql-area.cpp
+  test-output-pgsql-schema.cpp
+  test-output-pgsql-tablespace.cpp
+  test-output-pgsql-z_order.cpp
+  test-output-pgsql.cpp
+  test-parse-diff.cpp
+  test-parse-xml2.cpp
+  test-pgsql-escape.cpp
+)
+
+foreach (test ${TESTS})
+  get_filename_component(test_name ${test} NAME_WE)
+  add_executable(${test_name} ${test})
+  target_link_libraries(${test_name} osm2pgsql_lib common-pg middle-tests)
+  add_test(NAME ${test_name} COMMAND ${test_name}
+    WORKING_DIRECTORY ${osm2pgsql_SOURCE_DIR})
+  add_dependencies(check ${test_name})
+  message(STATUS "Added test: ${test_name}...")
+  set_tests_properties(${test_name} PROPERTIES TIMEOUT ${TESTING_TIMEOUT})
+endforeach()
+
+set(TEST_NODB
+ test-expire-tiles
+ test-middle-ram
+ test-options-database
+ test-options-parse
+ test-parse-diff
+ test-parse-xml2
+ test-pgsql-escape
+)
+
+foreach (test ${TEST_NODB})
+  set_property(TEST ${test} PROPERTY LABELS NoDB)
+endforeach()
+
+set_property(TEST test-middle-flat PROPERTY LABELS FlatNodes)
+set_property(TEST test-output-pgsql PROPERTY LABELS FlatNodes)
+
+find_package(PythonInterp)
+
+if (PYTHONINTERP_FOUND)
+  add_test(NAME regression-test-pbf COMMAND ${PYTHON_EXECUTABLE} tests/regression-test.py -f tests/liechtenstein-2013-08-03.osm.pbf -x $<TARGET_FILE:osm2pgsql>
+    WORKING_DIRECTORY ${osm2pgsql_SOURCE_DIR})
+  set_tests_properties(regression-test-pbf PROPERTIES TIMEOUT ${TESTING_TIMEOUT})
+  message(STATUS "Added test: regression-test-pbf (needs Python with psycopg2 module)")
+else()
+  message(WARNING "Can not find python, regression test disabled")
+endif()
diff --git a/tests/common-cleanup.cpp b/tests/common-cleanup.cpp
new file mode 100644
index 0000000..bfd0713
--- /dev/null
+++ b/tests/common-cleanup.cpp
@@ -0,0 +1,21 @@
+#include "common-cleanup.hpp"
+#include <boost/filesystem.hpp>
+
+namespace cleanup {
+
+file::file(const std::string &filename)
+  : m_filename(filename) {
+}
+
+file::~file() {
+  boost::system::error_code ec;
+  boost::filesystem::remove(m_filename, ec);
+  if (ec) {
+    // not a good idea to throw an exception from a destructor,
+    // so a warning will have to be good enough.
+    fprintf(stderr, "WARNING: Unable to remove \"%s\": %s\n",
+            m_filename.c_str(), ec.message().c_str());
+  }
+}
+
+} // namespace cleanup
diff --git a/tests/common-cleanup.hpp b/tests/common-cleanup.hpp
new file mode 100644
index 0000000..e5176c0
--- /dev/null
+++ b/tests/common-cleanup.hpp
@@ -0,0 +1,21 @@
+#ifndef COMMON_CLEANUP_HPP
+#define COMMON_CLEANUP_HPP
+
+#include <string>
+
+namespace cleanup {
+
+// RAII structure to remove a file upon destruction. doesn't create or do
+// anything to the file when it constructs.
+struct file {
+  file(const std::string &filename);
+  ~file();
+private:
+  // name of the file to be deleted upon destruction
+  std::string m_filename;
+};
+
+
+} // namespace cleanup
+
+#endif /* COMMON_CLEANUP_HPP */
diff --git a/tests/common-pg.cpp b/tests/common-pg.cpp
index 19d7e81..ad2b6b2 100644
--- a/tests/common-pg.cpp
+++ b/tests/common-pg.cpp
@@ -3,14 +3,13 @@
 #include <sstream>
 #include <cstdarg>
 #include <unistd.h>
+#include <memory>
 
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/make_shared.hpp>
 #include <boost/format.hpp>
-#include <boost/enable_shared_from_this.hpp>
 #include <boost/algorithm/string/predicate.hpp>
+#include <boost/lexical_cast.hpp>
 
 #ifdef _MSC_VER
 #include <windows.h>
@@ -24,11 +23,15 @@ namespace fs = boost::filesystem;
 namespace pg {
 
 conn_ptr conn::connect(const std::string &conninfo) {
-    return boost::shared_ptr<conn>(new conn(conninfo));
+    return std::shared_ptr<conn>(new conn(conninfo));
+}
+
+conn_ptr conn::connect(const database_options_t &database_options) {
+    return std::shared_ptr<conn>(new conn(database_options.conninfo()));
 }
 
 result_ptr conn::exec(const std::string &query) {
-    return boost::make_shared<result>(shared_from_this(), query);
+    return std::make_shared<result>(shared_from_this(), query);
 }
 
 result_ptr conn::exec(const boost::format &fmt) {
@@ -38,9 +41,9 @@ result_ptr conn::exec(const boost::format &fmt) {
 PGconn *conn::get() { return m_conn; }
 
 conn::~conn() {
-    if (m_conn != NULL) {
+    if (m_conn != nullptr) {
         PQfinish(m_conn);
-        m_conn = NULL;
+        m_conn = nullptr;
     }
 }
 
@@ -51,14 +54,14 @@ conn::conn(const std::string &conninfo)
         out << "Could not connect to database \"" << conninfo
             << "\" because: " << PQerrorMessage(m_conn);
         PQfinish(m_conn);
-        m_conn = NULL;
+        m_conn = nullptr;
         throw std::runtime_error(out.str());
     }
 }
 
 result::result(conn_ptr conn, const std::string &query)
     : m_conn(conn), m_result(PQexec(conn->get(), query.c_str())) {
-    if (m_result == NULL) {
+    if (m_result == nullptr) {
         throw std::runtime_error((boost::format("Unable to run query \"%1%\": NULL result")
                                   % query).str());
     }
@@ -67,17 +70,18 @@ result::result(conn_ptr conn, const std::string &query)
 PGresult *result::get() { return m_result; }
 
 result::~result() {
-    if (m_result != NULL) {
+    if (m_result != nullptr) {
         PQclear(m_result);
-        m_result = NULL;
+        m_result = nullptr;
     }
 }
 
 tempdb::tempdb()
-    : m_conn(conn::connect("dbname=postgres")) {
-    result_ptr res = NULL;
-    m_db_name = (boost::format("osm2pgsql-test-%1%-%2%") % getpid() % time(NULL)).str();
-    m_conn->exec(boost::format("DROP DATABASE IF EXISTS \"%1%\"") % m_db_name);
+    : m_postgres_conn(conn::connect("dbname=postgres"))
+{
+    result_ptr res = nullptr;
+    database_options.db = (boost::format("osm2pgsql-test-%1%-%2%") % getpid() % time(nullptr)).str();
+    m_postgres_conn->exec(boost::format("DROP DATABASE IF EXISTS \"%1%\"") % database_options.db);
     //tests can be run concurrently which means that this query can collide with other similar ones
     //so we implement a simple retry here to get around the case that they do collide if we dont
     //we often fail due to both trying to access template1 at the same time
@@ -86,7 +90,7 @@ tempdb::tempdb()
     while(status != PGRES_COMMAND_OK && retries++ < 20)
     {
         sleep(1);
-        res = m_conn->exec(boost::format("CREATE DATABASE \"%1%\" WITH ENCODING 'UTF8'") % m_db_name);
+        res = m_postgres_conn->exec(boost::format("CREATE DATABASE \"%1%\" WITH ENCODING 'UTF8'") % database_options.db);
         status = PQresultStatus(res->get());
     }
     if (PQresultStatus(res->get()) != PGRES_COMMAND_OK) {
@@ -94,11 +98,10 @@ tempdb::tempdb()
                                   % PQresultErrorMessage(res->get())).str());
     }
 
-    m_conninfo = (boost::format("dbname=%1%") % m_db_name).str();
-    conn_ptr db = conn::connect(m_conninfo);
+    m_conn = conn::connect(database_options);
 
-    setup_extension(db, "postgis", "postgis-1.5/postgis.sql", "postgis-1.5/spatial_ref_sys.sql", NULL);
-    setup_extension(db, "hstore", NULL);
+    setup_extension("postgis", {"postgis-1.5/postgis.sql", "postgis-1.5/spatial_ref_sys.sql"});
+    setup_extension("hstore");
 }
 
 void tempdb::check_tblspc() {
@@ -119,23 +122,98 @@ void tempdb::check_tblspc() {
 
 }
 
-tempdb::~tempdb() {
-    if (m_conn) {
-        m_conn->exec(boost::format("DROP DATABASE IF EXISTS \"%1%\"") % m_db_name);
+void tempdb::check_count(int expected, const std::string &query) {
+    pg::result_ptr res = m_conn->exec(query);
+    if (PQresultStatus(res->get()) != PGRES_TUPLES_OK) {
+        throw std::runtime_error((boost::format("Expected PGRES_TUPLES_OK but "
+                                                "got %1%. %2% Query was %3%.")
+                                  % PQresStatus(PQresultStatus(res->get()))
+                                  % PQresultErrorMessage(res->get())
+                                  % query).str());
+    }
+    int ntuples = PQntuples(res->get());
+    if (ntuples != 1) {
+        throw std::runtime_error((boost::format("Expected one tuple from a query to check "
+                                                "COUNT(*), but got %1%. Query was: %2%.")
+                                  % ntuples % query).str());
+    }
+
+    std::string numstr = PQgetvalue(res->get(), 0, 0);
+    int count = boost::lexical_cast<int>(numstr);
+
+    if (count != expected) {
+        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
+                                                "query: %3%.")
+                                  % expected % numstr % query).str());
     }
 }
 
-const std::string &tempdb::conninfo() const {
-    return m_conninfo;
+void tempdb::check_number(double expected, const std::string &query) {
+    pg::result_ptr res = m_conn->exec(query);
+
+    int ntuples = PQntuples(res->get());
+    if (ntuples != 1) {
+        throw std::runtime_error((boost::format("Expected only one tuple from a query, "
+                                                " but got %1%. Query was: %2%.")
+                                  % ntuples % query).str());
+    }
+
+    std::string numstr = PQgetvalue(res->get(), 0, 0);
+    double num = boost::lexical_cast<double>(numstr);
+
+    // floating point isn't exact, so allow a 0.01% difference
+    if ((num > 1.0001*expected) || (num < 0.9999*expected)) {
+        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
+                                                "query: %3%.")
+                                  % expected % num % query).str());
+    }
 }
 
-void tempdb::setup_extension(conn_ptr db, const std::string &extension, ...) {
+void tempdb::check_string(const std::string &expected, const std::string &query) {
+    pg::result_ptr res = m_conn->exec(query);
+
+    int ntuples = PQntuples(res->get());
+    if (ntuples != 1) {
+        throw std::runtime_error((boost::format("Expected only one tuple from a query, "
+                                                " but got %1%. Query was: %2%.")
+                                  % ntuples % query).str());
+    }
+
+    std::string actual = PQgetvalue(res->get(), 0, 0);
+
+    if (actual != expected) {
+        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
+                                                "query: %3%.")
+                                  % expected % actual % query).str());
+    }
+}
+
+void tempdb::assert_has_table(const std::string &table_name) {
+    std::string query = (boost::format("select count(*) from pg_catalog.pg_class "
+                                     "where oid = '%1%'::regclass")
+                       % table_name).str();
+
+    check_count(1, query);
+}
+
+tempdb::~tempdb() {
+    m_conn.reset(); // close the connection to the db
+    if (m_postgres_conn) {
+        m_postgres_conn->exec(boost::format("DROP DATABASE IF EXISTS \"%1%\"") % database_options.db);
+    }
+}
+
+void tempdb::setup_extension(const std::string &extension,
+                             const std::vector<std::string> &extension_files) {
     // first, try the new way of setting up extensions
-    result_ptr res = db->exec(boost::format("CREATE EXTENSION %1%") % extension);
+    result_ptr res = m_conn->exec(boost::format("CREATE EXTENSION %1%") % extension);
     if (PQresultStatus(res->get()) != PGRES_COMMAND_OK) {
+        if (extension_files.size() == 0) {
+            throw std::runtime_error((boost::format("Unable to load extension %1% and no files specified") % extension).str());
+        }
         // if that fails, then fall back to trying to find the files on
         // the filesystem to load to create the extension.
-        res = db->exec("select regexp_replace(split_part(version(),' ',2),'\\.[0-9]*$','');");
+        res = m_conn->exec("select regexp_replace(split_part(version(),' ',2),'\\.[0-9]*$','');");
 
         if ((PQresultStatus(res->get()) != PGRES_TUPLES_OK) ||
             (PQntuples(res->get()) != 1)) {
@@ -147,11 +225,10 @@ void tempdb::setup_extension(conn_ptr db, const std::string &extension, ...) {
         // TODO: make the contribdir configurable. Probably
         // only works on Debian-based distributions at the moment.
         fs::path contribdir = fs::path("/usr/share/postgresql/") / pg_version / fs::path("contrib");
-        va_list ap;
-        va_start(ap, extension);
-        const char *str = NULL;
-        while ((str = va_arg(ap, const char *)) != NULL) {
-            fs::path sql_file = contribdir / fs::path(str);
+
+        for (const auto& filename : extension_files) {
+            fs::path sql_file = contribdir / fs::path(filename);
+            // Should this throw an error if the file can't be found?
             if (fs::exists(sql_file) && fs::is_regular_file(sql_file)) {
                 size_t size = fs::file_size(sql_file);
                 std::string sql(size + 1, '\0');
@@ -162,7 +239,7 @@ void tempdb::setup_extension(conn_ptr db, const std::string &extension, ...) {
                                                             "load extension \"%2%\".")
                                               % sql_file % extension).str());
                 }
-                res = db->exec(sql);
+                res = m_conn->exec(sql);
                 if (PQresultStatus(res->get()) != PGRES_COMMAND_OK) {
                     throw std::runtime_error((boost::format("Could not load extension \"%1%\": %2%")
                                               % extension
@@ -170,7 +247,6 @@ void tempdb::setup_extension(conn_ptr db, const std::string &extension, ...) {
                 }
             }
         }
-        va_end(ap);
     }
 }
 } // namespace pg
diff --git a/tests/common-pg.hpp b/tests/common-pg.hpp
index faa2888..32f727a 100644
--- a/tests/common-pg.hpp
+++ b/tests/common-pg.hpp
@@ -2,13 +2,14 @@
 #define COMMON_PG_HPP
 
 #include <string>
-#include <boost/shared_ptr.hpp>
+#include <memory>
 #include <boost/format.hpp>
 #include <boost/noncopyable.hpp>
-#include <boost/enable_shared_from_this.hpp>
-
 #include <libpq-fe.h>
 
+// reuse the database_options_t class
+#include "options.hpp"
+
 /* Some RAII objects to make writing stuff that needs a temporary database
  * easier, and to keep track of and free connections and results objects.
  */
@@ -17,14 +18,15 @@ namespace pg {
 struct conn;
 struct result;
 
-typedef boost::shared_ptr<conn> conn_ptr;
-typedef boost::shared_ptr<result> result_ptr;
+typedef std::shared_ptr<conn> conn_ptr;
+typedef std::shared_ptr<result> result_ptr;
 
 struct conn
     : public boost::noncopyable,
-      public boost::enable_shared_from_this<conn> {
+      public std::enable_shared_from_this<conn> {
 
     static conn_ptr connect(const std::string &conninfo);
+    static conn_ptr connect(const database_options_t &database_options);
     result_ptr exec(const std::string &query);
     result_ptr exec(const boost::format &fmt);
     PGconn *get();
@@ -54,16 +56,53 @@ struct tempdb
     tempdb();
     ~tempdb();
 
-    const std::string &conninfo() const;
+    database_options_t database_options;
 
     void check_tblspc();
+    /**
+     * Checks the result of a query with COUNT(*).
+     * It will work with any integer-returning query.
+     * \param[in] expected expected result
+     * \param[in] query SQL query to run. Must return one tuple.
+     * \throws std::runtime_error if query result is not expected
+     */
+    void check_count(int expected, const std::string &query);
+
+    /**
+     * Checks a floating point number.
+     * It allows a small variance around the expected result to allow for
+     * floating point differences.
+     * The query must only return one tuple
+     * \param[in] expected expected result
+     * \param[in] query SQL query to run. Must return one tuple.
+     * \throws std::runtime_error if query result is not expected
+     */
+    void check_number(double expected, const std::string &query);
+
+    /**
+     * Check the string a query returns.
+     * \param[in] expected expected result
+     * \param[in] query SQL query to run. Must return one tuple.
+     * \throws std::runtime_error if query result is not expected
+     */
+    void check_string(const std::string &expected, const std::string &query);
+    /**
+     * Assert that the database has a certain table_name
+     * \param[in] table_name Name of the table to check, optionally schema-qualified
+     * \throws std::runtime_error if missing the table
+     */
+    void assert_has_table(const std::string &table_name);
 
 private:
-    void setup_extension(conn_ptr db, const std::string &extension, ...);
-
-    conn_ptr m_conn;
-    std::string m_db_name;
-    std::string m_conninfo;
+    /**
+     * Sets up an extension, trying first with 9.1 CREATE EXTENSION, and falling
+     * back to trying to find extension_files. The fallback is not likely to
+     * work on systems not based on Debian.
+     */
+    void setup_extension(const std::string &extension, const std::vector<std::string> &extension_files = std::vector<std::string>());
+
+    conn_ptr m_conn; ///< connection to the test DB
+    conn_ptr m_postgres_conn; ///< Connection to the "postgres" db, used to create and drop test DBs
 };
 
 } // namespace pg
diff --git a/tests/common.hpp b/tests/common.hpp
new file mode 100644
index 0000000..3f602f6
--- /dev/null
+++ b/tests/common.hpp
@@ -0,0 +1,22 @@
+#ifndef TEST_COMMON_HPP
+#define TEST_COMMON_HPP
+
+#include "options.hpp"
+#include "osmdata.hpp"
+#include "parse-osmium.hpp"
+
+namespace testing {
+
+    void parse(const char *filename, const char *format,
+                const options_t &options, osmdata_t *osmdata)
+    {
+        parse_osmium_t parser(options.extra_attributes, options.bbox,
+                              options.projection.get(), options.append, osmdata);
+
+        osmdata->start();
+        parser.stream_file(filename, format);
+        osmdata->stop();
+    }
+}
+
+#endif /* TEST_COMMON_HPP */
diff --git a/tests/hstore-match-only.osm b/tests/hstore-match-only.osm
new file mode 100644
index 0000000..4cf06f1
--- /dev/null
+++ b/tests/hstore-match-only.osm
@@ -0,0 +1,323 @@
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+test dataset for hstore-match-only function of osm2pgsql
+
+This file contains 19 tagged ways and 7 tagged nodes
+
+Using the provided hstore-match-only.style file and the hstore as well as
+hstore-match-only commandline option we end up with a database containing
+6 points, 7 polygons and 12 lines:
+
+gis=> select count(*) from planet_osm_point;
+ count
+     6
+(1 row)
+gis=> select count(*) from planet_osm_polygon;
+ count
+     7
+(1 row)
+
+gis=> select count(*) from planet_osm_line;
+ count
+    12
+(1 row)
+-->
+
+<osm version='0.6' upload='false' generator='JOSM'>
+  <node id='6' visible='true' version='1' lat='49.05153222821' lon='8.07892280714' />
+  <node id='8' visible='true' version='1' lat='49.05160942246' lon='8.07685590746' />
+  <node id='10' visible='true' version='1' lat='49.05266928632' lon='8.07991140766' />
+  <node id='12' visible='true' version='1' lat='49.05305485258' lon='8.07803155655' />
+  <node id='14' visible='true' version='1' lat='49.05260999334' lon='8.07646785276' />
+  <node id='16' visible='true' version='1' lat='49.03515657968' lon='8.13942160317' />
+  <node id='18' visible='true' version='1' lat='48.98613332441' lon='8.33058309563' />
+  <node id='20' visible='true' version='1' lat='49.11989047093' lon='8.33058309563' />
+  <node id='22' visible='true' version='1' lat='49.11518682447' lon='8.15523195217' />
+  <node id='24' visible='true' version='1' lat='48.99509309991' lon='8.17679151899' />
+  <node id='26' visible='true' version='1' lat='49.02337655032' lon='8.3772954904' />
+  <node id='28' visible='true' version='1' lat='49.10671913679' lon='8.37370222926' />
+  <node id='30' visible='true' version='1' lat='49.07565858296' lon='8.4089161884'>
+    <tag k='historic' v='castle' />
+    <tag k='ruined' v='yes' />
+  </node>
+  <node id='32' visible='true' version='1' lat='49.03138727373' lon='8.51024615245' />
+  <node id='34' visible='true' version='1' lat='48.933757167' lon='8.44772340868' />
+  <node id='36' visible='true' version='1' lat='48.92714725897' lon='8.10277033957' />
+  <node id='38' visible='true' version='1' lat='48.96443456342' lon='8.03018646462' />
+  <node id='40' visible='true' version='1' lat='49.15797356916' lon='8.09989573067' />
+  <node id='42' visible='true' version='1' lat='49.03358637848' lon='7.99017805251' />
+  <node id='44' visible='true' version='1' lat='48.92713658981' lon='8.20221643712' />
+  <node id='46' visible='true' version='1' lat='49.12020833896' lon='8.4870044058' />
+  <node id='48' visible='true' version='1' lat='49.09795155433' lon='8.01122065379' />
+  <node id='50' visible='true' version='1' lat='49.06402712622' lon='8.06789282649' />
+  <node id='52' visible='true' version='1' lat='49.06318018297' lon='8.06973971479' />
+  <node id='54' visible='true' version='1' lat='49.0645445515' lon='8.07119709293' />
+  <node id='56' visible='true' version='1' lat='49.0653914715' lon='8.06935020463' />
+  <node id='58' visible='true' version='1' lat='49.06423960402' lon='8.06957831599'>
+    <tag k='amenity' v='prison' />
+  </node>
+  <node id='60' visible='true' version='1' lat='49.0858769851' lon='8.19763560952' />
+  <node id='62' visible='true' version='1' lat='49.08987054796' lon='8.35211742394' />
+  <node id='64' visible='true' version='1' lat='49.03393143573' lon='8.41563790685' />
+  <node id='66' visible='true' version='1' lat='49.09353103175' lon='8.36736233984' />
+  <node id='68' visible='true' version='1' lat='49.02926700076' lon='8.344494966' />
+  <node id='70' visible='true' version='1' lat='49.03059974109' lon='8.29266225195' />
+  <node id='72' visible='true' version='1' lat='49.07988603855' lon='8.1813743659' />
+  <node id='74' visible='true' version='1' lat='48.99860411956' lon='8.13411512662' />
+  <node id='76' visible='true' version='1' lat='49.05910165734' lon='8.41044514247' />
+  <node id='78' visible='true' version='1' lat='49.05910787132' lon='8.41060121724' />
+  <node id='80' visible='true' version='1' lat='49.05918164083' lon='8.41059437718' />
+  <node id='82' visible='true' version='1' lat='49.05917542687' lon='8.4104383024' />
+  <node id='84' visible='true' version='1' lat='49.0571059179' lon='8.41070821764'>
+    <tag k='addr:housenumber' v='42' />
+  </node>
+  <node id='86' visible='true' version='1' lat='49.00485239659' lon='8.10591725672' />
+  <node id='88' visible='true' version='1' lat='49.08085222575' lon='8.08283939451' />
+  <node id='90' visible='true' version='1' lat='48.98423743896' lon='8.11845937143' />
+  <node id='92' visible='true' version='1' lat='49.10319099594' lon='8.11917802366' />
+  <node id='94' visible='true' version='1' lat='49.05904839499' lon='8.41049417747' />
+  <node id='96' visible='true' version='1' lat='49.05471933562' lon='8.06849989751' />
+  <node id='117' visible='true' version='1' lat='49.16700513707' lon='8.12518444414' />
+  <node id='118' visible='true' version='1' lat='49.13091446704' lon='8.08644347959' />
+  <node id='120' visible='true' version='1' lat='49.11055388122' lon='8.05181140521' />
+  <node id='122' visible='true' version='1' lat='49.08710965227' lon='8.04476759347' />
+  <node id='124' visible='true' version='1' lat='49.04634415702' lon='8.0512244209' />
+  <node id='126' visible='true' version='1' lat='49.02402435131' lon='8.05944220126' />
+  <node id='128' visible='true' version='1' lat='49.0013094457' lon='8.06237712282' />
+  <node id='130' visible='true' version='1' lat='48.93503056586' lon='8.05415934246' />
+  <node id='214' visible='true' version='1' lat='49.11746633187' lon='8.24020952552' />
+  <node id='216' visible='true' version='1' lat='49.05813441994' lon='8.14395837697' />
+  <node id='218' visible='true' version='1' lat='49.06140528217' lon='8.37565665399' />
+  <node id='221' visible='true' version='1' lat='49.05582697806' lon='8.37589712773' />
+  <node id='224' visible='true' version='1' lat='49.05309372735' lon='8.14296295673' />
+  <node id='284' visible='true' version='1' lat='49.04978920459' lon='8.07928222396' />
+  <node id='285' visible='true' version='1' lat='49.04992522037' lon='8.08353659497' />
+  <node id='287' visible='true' version='1' lat='49.04679676328' lon='8.08332906468' />
+  <node id='289' visible='true' version='1' lat='49.04768091241' lon='8.0795935194' />
+  <node id='304' visible='true' version='1' lat='49.01555628571' lon='8.07933310333'>
+    <tag k='name' v='Nowhere' />
+    <tag k='place' v='hamlet' />
+  </node>
+  <node id='317' visible='true' version='1' lat='49.01825104522' lon='8.40804431774'>
+    <tag k='power' v='tower' />
+  </node>
+  <node id='328' visible='true' version='1' lat='49.10094761615' lon='8.03120038979' />
+  <node id='329' visible='true' version='1' lat='49.06519342756' lon='8.0265045153' />
+  <node id='331' visible='true' version='1' lat='49.02517975693' lon='8.03237435841' />
+  <node id='333' visible='true' version='1' lat='48.99399295757' lon='8.03589626428' />
+  <node id='335' visible='true' version='1' lat='48.98012588722' lon='8.03707023291' />
+  <node id='337' visible='true' version='1' lat='48.94968184469' lon='8.03002642117' />
+  <node id='339' visible='true' version='1' lat='49.13590798222' lon='8.03530927997' />
+  <node id='361' visible='true' version='1' lat='49.0105513453' lon='8.42271892552' />
+  <node id='363' visible='true' version='1' lat='48.99168204717' lon='8.4162620981' />
+  <node id='365' visible='true' version='1' lat='48.99399295757' lon='8.44972020385' />
+  <node id='367' visible='true' version='1' lat='48.9781996' lon='8.45500306265' />
+  <node id='436' visible='true' version='1' lat='49.0371102771' lon='8.0728762759'>
+    <tag k='shop' v='beverages' />
+  </node>
+  <node id='444' visible='true' version='1' lat='48.98608722574' lon='8.37533796274'>
+    <tag k='foo' v='bar' />
+    <tag k='name' v='senseless tag on node' />
+  </node>
+  <node id='445' visible='true' version='1' lat='48.98513388557' lon='8.41743606672' />
+  <node id='447' visible='true' version='1' lat='48.97434680224' lon='8.41978400397' />
+  <node id='449' visible='true' version='1' lat='48.96440559803' lon='8.38103588213' />
+  <node id='1116' visible='true' version='1' lat='49.10432671853' lon='7.99302782947' />
+  <node id='1117' visible='true' version='1' lat='49.14365414527' lon='8.06119495067' />
+  <node id='1119' visible='true' version='1' lat='49.17122342967' lon='8.1015570619' />
+  <node id='1121' visible='true' version='1' lat='49.17298265023' lon='8.15088853119' />
+  <node id='1123' visible='true' version='1' lat='49.14834787313' lon='8.35090521576' />
+  <node id='1125' visible='true' version='1' lat='49.13954676867' lon='8.48454865074' />
+  <node id='1127' visible='true' version='1' lat='49.12428781794' lon='8.50517817426' />
+  <node id='1129' visible='true' version='1' lat='49.08788213472' lon='8.52132301875' />
+  <node id='1131' visible='true' version='1' lat='49.0102842774' lon='8.52849850519' />
+  <node id='1133' visible='true' version='1' lat='48.9502393357' lon='8.48096090752' />
+  <node id='1135' visible='true' version='1' lat='48.91842154869' lon='8.45674364077' />
+  <node id='1137' visible='true' version='1' lat='48.91488498718' lon='8.289913581' />
+  <node id='1139' visible='true' version='1' lat='48.91193766133' lon='8.10783561254' />
+  <node id='1141' visible='true' version='1' lat='48.91783213916' lon='8.05760720744' />
+  <node id='1143' visible='true' version='1' lat='48.95200639595' lon='8.00379105913' />
+  <node id='1145' visible='true' version='1' lat='49.03381156891' lon='7.95894426887' />
+  <node id='1147' visible='true' version='1' lat='49.0861198919' lon='7.97508911336' />
+  <way id='107' visible='true' version='1'>
+    <nd ref='46' />
+    <nd ref='32' />
+    <nd ref='34' />
+    <nd ref='44' />
+    <nd ref='36' />
+    <tag k='admin_level' v='3' />
+    <tag k='boundary' v='administrative' />
+  </way>
+  <way id='98' visible='true' version='1'>
+    <nd ref='14' />
+    <nd ref='12' />
+    <nd ref='10' />
+    <nd ref='6' />
+    <nd ref='8' />
+    <nd ref='14' />
+    <tag k='leisure' v='playground' />
+  </way>
+  <way id='102' visible='true' version='1'>
+    <nd ref='36' />
+    <nd ref='38' />
+    <nd ref='42' />
+    <nd ref='48' />
+    <nd ref='40' />
+    <nd ref='46' />
+    <tag k='admin_level' v='3' />
+    <tag k='boundary' v='administrative' />
+  </way>
+  <way id='104' visible='true' version='1'>
+    <nd ref='56' />
+    <nd ref='54' />
+    <nd ref='52' />
+    <nd ref='50' />
+    <nd ref='56' />
+    <tag k='barrier' v='wall' />
+  </way>
+  <way id='106' visible='true' version='1'>
+    <nd ref='82' />
+    <nd ref='80' />
+    <nd ref='78' />
+    <nd ref='76' />
+    <nd ref='82' />
+    <tag k='addr:housenumber' v='23' />
+    <tag k='building' v='yes' />
+  </way>
+  <way id='108' visible='true' version='1'>
+    <nd ref='88' />
+    <nd ref='86' />
+    <nd ref='74' />
+    <nd ref='72' />
+    <nd ref='60' />
+    <nd ref='70' />
+    <nd ref='68' />
+    <nd ref='62' />
+    <nd ref='66' />
+    <nd ref='64' />
+    <tag k='highway' v='unclassified' />
+  </way>
+  <way id='110' visible='true' version='1'>
+    <nd ref='92' />
+    <nd ref='90' />
+    <tag k='aeroway' v='runway' />
+  </way>
+  <way id='112' visible='true' version='1'>
+    <nd ref='96' />
+    <nd ref='94' />
+    <tag k='aerialway' v='chair_lift' />
+  </way>
+  <way id='119' visible='true' version='1'>
+    <nd ref='117' />
+    <nd ref='118' />
+    <nd ref='120' />
+    <nd ref='122' />
+    <nd ref='124' />
+    <tag k='waterway' v='river' />
+    <tag k='width' v='30' />
+  </way>
+  <way id='135' visible='true' version='1'>
+    <nd ref='124' />
+    <nd ref='126' />
+    <tag k='lock' v='yes' />
+  </way>
+  <way id='136' visible='true' version='1'>
+    <nd ref='126' />
+    <nd ref='128' />
+    <nd ref='130' />
+    <tag k='waterway' v='river' />
+    <tag k='width' v='30' />
+  </way>
+  <way id='219' visible='true' version='1'>
+    <nd ref='216' />
+    <nd ref='218' />
+    <nd ref='221' />
+    <nd ref='224' />
+    <nd ref='216' />
+    <tag k='man_made' v='cutline' />
+  </way>
+  <way id='228' visible='true' version='1'>
+    <nd ref='221' />
+    <nd ref='26' />
+    <nd ref='18' />
+    <nd ref='24' />
+    <nd ref='16' />
+    <nd ref='224' />
+    <nd ref='221' />
+    <tag k='landuse' v='forest' />
+  </way>
+  <way id='243' visible='true' version='1'>
+    <nd ref='216' />
+    <nd ref='22' />
+    <nd ref='214' />
+    <nd ref='20' />
+    <nd ref='28' />
+    <nd ref='218' />
+    <nd ref='216' />
+    <tag k='landuse' v='forest' />
+  </way>
+  <way id='286' visible='true' version='1'>
+    <nd ref='284' />
+    <nd ref='285' />
+    <nd ref='287' />
+    <nd ref='289' />
+    <nd ref='284' />
+    <tag k='military' v='barracks' />
+  </way>
+  <way id='330' visible='true' version='1'>
+    <nd ref='339' />
+    <nd ref='328' />
+    <nd ref='329' />
+    <nd ref='331' />
+    <nd ref='333' />
+    <nd ref='335' />
+    <nd ref='337' />
+    <tag k='railway' v='rail' />
+  </way>
+  <way id='369' visible='true' version='1'>
+    <nd ref='64' />
+    <nd ref='361' />
+    <nd ref='363' />
+    <nd ref='365' />
+    <nd ref='367' />
+    <tag k='highway' v='track' />
+  </way>
+  <way id='446' visible='true' version='1'>
+    <nd ref='444' />
+    <nd ref='445' />
+    <nd ref='447' />
+    <nd ref='449' />
+    <nd ref='444' />
+    <tag k='tourism' v='zoo' />
+  </way>
+  <way id='1118' visible='true' version='1'>
+    <nd ref='1116' />
+    <nd ref='1117' />
+    <nd ref='1119' />
+    <nd ref='1121' />
+    <nd ref='1123' />
+    <nd ref='1125' />
+    <nd ref='1127' />
+    <nd ref='1129' />
+    <nd ref='1131' />
+    <nd ref='1133' />
+    <nd ref='1135' />
+    <nd ref='1137' />
+    <nd ref='1139' />
+    <nd ref='1141' />
+    <nd ref='1143' />
+    <nd ref='1145' />
+    <nd ref='1147' />
+    <nd ref='1116' />
+    <tag k='foo' v='bar' />
+    <tag k='name' v='senseless way' />
+  </way>
+  <relation id='384' visible='true' version='1'>
+    <member type='way' ref='369' role='' />
+    <member type='way' ref='108' role='' />
+    <tag k='name' v='my cycle route' />
+    <tag k='route' v='bicycle' />
+    <tag k='type' v='route' />
+  </relation>
+</osm>
diff --git a/tests/hstore-match-only.style b/tests/hstore-match-only.style
new file mode 100644
index 0000000..f99aaea
--- /dev/null
+++ b/tests/hstore-match-only.style
@@ -0,0 +1,31 @@
+# hstore only Database schema which stores only objects
+# with one of the important tags defined here
+#
+# this only makes sense when --hstore-match-only is used
+#
+node,way   aerialway    text         linear,nocolumn
+node,way   addr:housenumber text     linear,nocolumn
+node,way   aeroway      text         polygon,nocolumn
+node,way   amenity      text         polygon,nocolumn
+node,way   barrier      text         linear,nocolumn
+node,way   boundary     text         linear,nocolumn
+node,way   building     text         polygon,nocolumn
+node,way   highway      text         linear,nocolumn
+node,way   historic     text         polygon,nocolumn
+node,way   landuse      text         polygon,nocolumn
+node,way   leisure      text         polygon,nocolumn
+node,way   lock         text         linear,nocolumn
+node,way   man_made     text         polygon,nocolumn
+node,way   military     text         polygon,nocolumn
+node,way   place        text         polygon,nocolumn
+node,way   power        text         polygon,nocolumn
+node,way   railway      text         linear,nocolumn
+node,way   route        text         linear,nocolumn
+node,way   shop         text         polygon,nocolumn
+node,way   tourism      text         polygon,nocolumn
+node,way   waterway     text         polygon,nocolumn
+node,way   natural      text         polygon,nocolumn
+
+node,way   z_order      int4         linear # This is calculated during import
+way        way_area     real                # This is calculated during import
+
diff --git a/tests/liechtenstein-2013-08-03.osm.bz2 b/tests/liechtenstein-2013-08-03.osm.bz2
deleted file mode 100644
index 4db9ac8..0000000
Binary files a/tests/liechtenstein-2013-08-03.osm.bz2 and /dev/null differ
diff --git a/tests/middle-tests.cpp b/tests/middle-tests.cpp
index e6df830..59c0d6d 100644
--- a/tests/middle-tests.cpp
+++ b/tests/middle-tests.cpp
@@ -9,7 +9,7 @@
 #include "osmtypes.hpp"
 #include "tests/middle-tests.hpp"
 
-#define BLOCK_SHIFT 10
+#define BLOCK_SHIFT 13
 #define PER_BLOCK  (((osmid_t)1) << BLOCK_SHIFT)
 
 struct expected_node {
@@ -47,7 +47,7 @@ int test_node_set(middle_t *mid)
   nodelist_t nodes;
 
   // set the node
-  if (mid->nodes_set(expected.id, expected.lat, expected.lon, tags) != 0) { std::cerr << "ERROR: Unable to set node.\n"; return 1; }
+  mid->nodes_set(expected.id, expected.lat, expected.lon, tags);
 
   // get it back
   ids.push_back(expected.id);
@@ -113,12 +113,7 @@ int test_nodes_comprehensive_set(middle_t *mid)
 
   for (expected_nodelist_t::iterator node = expected_nodes.begin(); node != expected_nodes.end(); ++node)
   {
-    if (mid->nodes_set(node->id, node->lat, node->lon, tags) != 0)
-    {
-      std::cerr << "ERROR: Unable to set node " << node->id << "with lat="
-                << node->lat << " lon=" << node->lon << std::endl;
-      return 1;
-    }
+    mid->nodes_set(node->id, node->lat, node->lon, tags);
     ids.push_back(node->id);
   }
 
@@ -167,21 +162,18 @@ int test_way_set(middle_t *mid)
   double lat = 12.3456789;
   double lon = 98.7654321;
   taglist_t tags;
-  struct osmNode *node_ptr = NULL;
-  int status = 0;
+  struct osmNode *node_ptr = nullptr;
   idlist_t nds;
   for (osmid_t i = 1; i <= 10; ++i)
       nds.push_back(i);
 
   // set the nodes
   for (size_t i = 0; i < nds.size(); ++i) {
-    status = mid->nodes_set(nds[i], lat, lon, tags);
-    if (status != 0) { std::cerr << "ERROR: Unable to set node " << nds[i] << ".\n"; return 1; }
+    mid->nodes_set(nds[i], lat, lon, tags);
   }
 
   // set the way
-  status = mid->ways_set(way_id, nds, tags);
-  if (status != 0) { std::cerr << "ERROR: Unable to set way.\n"; return 1; }
+  mid->ways_set(way_id, nds, tags);
 
   // commit the setup data
   mid->commit();
@@ -191,7 +183,7 @@ int test_way_set(middle_t *mid)
   ways.push_back(way_id);
   std::vector<taglist_t> xtags;
   multinodelist_t xnodes;
-  int way_count = mid->ways_get_list(ways, xways, xtags, xnodes);
+  size_t way_count = mid->ways_get_list(ways, xways, xtags, xnodes);
   if (way_count != 1) { std::cerr << "ERROR: Unable to get way list.\n"; return 1; }
 
   // check that it's the same
@@ -236,8 +228,7 @@ int test_way_set(middle_t *mid)
       // finally, try touching a node on a non-pending way. that should
       // make it become pending. we just checked that the way is not
       // pending, so any change must be due to the node changing.
-      status = slim->node_changed(nds[0]);
-      if (status != 0) { std::cerr << "ERROR: Unable to reset node.\n"; return 1; }
+      slim->node_changed(nds[0]);
       slim->iterate_ways(tpp);
       if (slim->pending_count() != 1) {
           std::cerr << "ERROR: Was expecting a single pending way from node update, but got "
diff --git a/tests/mockups.hpp b/tests/mockups.hpp
new file mode 100644
index 0000000..8084840
--- /dev/null
+++ b/tests/mockups.hpp
@@ -0,0 +1,116 @@
+#ifndef TESTS_MOCKUPS_HPP
+#define TESTS_MOCKUPS_HPP
+
+#include "middle.hpp"
+#include "output.hpp"
+
+struct dummy_middle_t : public middle_t {
+    virtual ~dummy_middle_t() = default;
+
+    void start(const options_t *) { }
+    void stop(void) { }
+    void cleanup(void) { }
+    void analyze(void) { }
+    void end(void) { }
+    void commit(void) { }
+
+    void nodes_set(osmid_t, double, double, const taglist_t &) { }
+    size_t nodes_get_list(nodelist_t &, const idlist_t) const { return 0; }
+
+    void ways_set(osmid_t, const idlist_t &, const taglist_t &) { }
+    bool ways_get(osmid_t, taglist_t &, nodelist_t &) const { return true; }
+    size_t ways_get_list(const idlist_t &, idlist_t &,
+                              std::vector<taglist_t> &,
+                              std::vector<nodelist_t> &) const { return 0; }
+
+    void relations_set(osmid_t, const memberlist_t &, const taglist_t &) { }
+    bool relations_get(osmid_t, memberlist_t &, taglist_t &) const { return 0; }
+
+    void iterate_ways(pending_processor&) { }
+    void iterate_relations(pending_processor&) { }
+
+    virtual size_t pending_count() const { return 0; }
+
+    std::vector<osmid_t> relations_using_way(osmid_t) const { return std::vector<osmid_t>(); }
+
+    virtual std::shared_ptr<const middle_query_t> get_instance() const {return std::shared_ptr<const middle_query_t>();}
+};
+
+struct dummy_slim_middle_t : public slim_middle_t {
+    virtual ~dummy_slim_middle_t() = default;
+
+    void start(const options_t *) { }
+    void stop(void) { }
+    void cleanup(void) { }
+    void analyze(void) { }
+    void end(void) { }
+    void commit(void) { }
+
+    void nodes_set(osmid_t, double, double, const taglist_t &) { }
+    size_t nodes_get_list(nodelist_t &, const idlist_t) const { return 0; }
+
+    void ways_set(osmid_t, const idlist_t &, const taglist_t &) { }
+    bool ways_get(osmid_t, taglist_t &, nodelist_t &) const { return true; }
+    size_t ways_get_list(const idlist_t &, idlist_t &,
+                              std::vector<taglist_t> &,
+                              std::vector<nodelist_t> &) const { return 0; }
+
+    void relations_set(osmid_t, const memberlist_t &, const taglist_t &) { }
+    bool relations_get(osmid_t, memberlist_t &, taglist_t &) const { return 0; }
+
+    void iterate_ways(pending_processor&) { }
+    void iterate_relations(pending_processor&) { }
+
+    size_t pending_count() const { return 0; }
+
+    std::vector<osmid_t> relations_using_way(osmid_t) const { return std::vector<osmid_t>(); }
+
+    std::shared_ptr<const middle_query_t> get_instance() const {return std::shared_ptr<const middle_query_t>();}
+
+    void nodes_delete(osmid_t) {};
+    void node_changed(osmid_t) {};
+
+    void ways_delete(osmid_t) {};
+    void way_changed(osmid_t) {};
+
+    void relations_delete(osmid_t) {};
+    void relation_changed(osmid_t) {};
+};
+
+struct dummy_output_t : public output_t {
+
+    explicit dummy_output_t(const options_t &options_)
+        : output_t(nullptr, options_) {
+    }
+
+    virtual ~dummy_output_t() = default;
+
+    int node_add(osmid_t, double, double, const taglist_t &) { return 0; }
+    int way_add(osmid_t, const idlist_t &, const taglist_t &) { return 0; }
+    int relation_add(osmid_t, const memberlist_t &, const taglist_t &) { return 0; }
+
+    int start() { return 0; }
+    int connect(int) { return 0; }
+    void stop() { }
+    void commit() { }
+    void cleanup(void) { }
+    void close(int) { }
+
+    void enqueue_ways(pending_queue_t &, osmid_t, size_t, size_t&) { }
+    int pending_way(osmid_t, int) { return 0; }
+
+    void enqueue_relations(pending_queue_t &, osmid_t, size_t, size_t&) { }
+    int pending_relation(osmid_t, int) { return 0; }
+
+    int node_modify(osmid_t, double, double, const taglist_t &) { return 0; }
+    int way_modify(osmid_t, const idlist_t &, const taglist_t &) { return 0; }
+    int relation_modify(osmid_t, const memberlist_t &, const taglist_t &) { return 0; }
+
+    int node_delete(osmid_t) { return 0; }
+    int way_delete(osmid_t) { return 0; }
+    int relation_delete(osmid_t) { return 0; }
+
+};
+
+#endif
+
diff --git a/tests/regression-test.py b/tests/regression-test.py
index 4ebcef6..d1c0b81 100755
--- a/tests/regression-test.py
+++ b/tests/regression-test.py
@@ -6,6 +6,7 @@ import os
 import fnmatch
 import subprocess
 
+exe_path="./osm2pgsql"
 full_import_file="tests/liechtenstein-2013-08-03.osm.pbf"
 multipoly_import_file="tests/test_multipolygon.osm" #This file contains a number of different multi-polygon test cases
 diff_import_file="tests/000466354.osc.gz"
@@ -188,7 +189,7 @@ sql_test_statements=[
       'SELECT round(sum(ST_Area(way))) FROM planet_osm_polygon WHERE osm_id = 112 and "natural" = \'heath\'', 1234),
     #**** Test to check that only polygon tags that are present on all outer ways get copied over to the multi-polygon relation ****
     ( 106, 'Multipolygon copy outer tags (presence of relation)',
-      'SELECT round(sum(ST_Area(way))) FROM planet_osm_polygon WHERE osm_id = -38 and "natural" = \'water\'', 29340),
+      'SELECT round(sum(ST_Area(way))) FROM planet_osm_polygon WHERE osm_id = -38 and "natural" = \'water\'', 29341),
     ( 107, 'Multipolygon copy outer tags (absence of partial outer tags)',
       'SELECT count(*) FROM planet_osm_polygon WHERE osm_id = -38 and "natural" = \'water\' and "man_made" = \'pier\'', 0),
     ( 108, 'Multipolygon copy outer tags (absence of multi-polygon tagged outer way)',
@@ -209,7 +210,7 @@ sql_test_statements=[
       'SELECT round(sum(ST_length(way))) FROM planet_osm_line WHERE (osm_id = 127 OR osm_id = 122) AND "man_made" = \'pier\'', 318),
     #**** Test to check that if polygon tags are on both outer ways and relation, polygons don't get duplicated in the db ****
     ( 116, 'Multipolygon tags on both outer and relation (presence of relation)',
-      'SELECT round(sum(ST_Area(way))) FROM planet_osm_polygon WHERE osm_id = -39 and "landuse" = \'forest\'', 10379),
+      'SELECT round(sum(ST_Area(way))) FROM planet_osm_polygon WHERE osm_id = -39 and "landuse" = \'forest\'', 10378),
     ( 117, 'Multipolygon tags on both outer and relation (absence of outer way)',
       'SELECT count(*) FROM planet_osm_polygon WHERE osm_id = 138', 0),
     ( 118, 'Multipolygon tags on both outer and relation with additional tags on relation (presence of relation)',
@@ -251,11 +252,11 @@ class SlimRenderingTestSuite(unittest.TestSuite):
         self.addTest(BasicSlimTestCase("Hstore name column", ["-z", "name:"], [0,1,2,3],[6,7,8,9]))
         self.addTest(BasicSlimTestCase("Hstore", ["-k"], [51,52,53,54],[55,56,57,58]))
         self.addTest(BasicSlimTestCase("Hstore all", ["-j"], [51,52,53,54,93,94,95,96],[55,56,57,58, 97, 98, 99, 100]))
-        self.addTest(BasicSlimTestCase("Hstore index", ["--hstore", "--hstore-add-index"], [51,52,53,54],[55,56,57,58]))        
+        self.addTest(BasicSlimTestCase("Hstore index", ["--hstore", "--hstore-add-index"], [51,52,53,54],[55,56,57,58]))
         #tests dont check for osm_timestamp which is currently missing in the pbf parser
         self.addTest(BasicSlimTestCase("Extra tags hstore match only", ["-x", "-k", "--hstore-match-only"], [0,1,2,3],[6,7,8,9]))
         self.addTest(BasicSlimTestCase("Extra tags hstore all", ["-j", "-x"], [51,52,53,54,59,60,61],[55,56,57,58]))
-        
+
         self.addTest(BasicSlimTestCase("--tablespace-main-data", ["--tablespace-main-data", "tablespacetest"], [0,1,2,3,13,91,92],[6,7,8,9]))
         self.addTest(BasicSlimTestCase("--tablespace-main-index", ["--tablespace-main-index", "tablespacetest"], [0,1,2,3,13,91,92],[6,7,8,9]))
         self.addTest(BasicSlimTestCase("--tablespace-slim-data", ["--tablespace-slim-data", "tablespacetest"], [0,1,2,3,13,91,92],[6,7,8,9]))
@@ -369,36 +370,36 @@ class BaseTestCase(unittest.TestCase):
 #****************************************************************
 
 class BaseNonSlimTestCase(BaseTestCase):
-    
+
     def setUpGeneric(self, parameters, file):
-        proc = subprocess.Popen(["./osm2pgsql", "-Sdefault.style", "-dosm2pgsql-test", "-C100"] + parameters + [full_import_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        proc = subprocess.Popen([exe_path, "-Sdefault.style", "-dosm2pgsql-test", "-C100"] + parameters + [full_import_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         (outp, outerr) = proc.communicate()
         self.assertEqual (proc.returncode, 0, "Execution of osm2pgsql with options: '%s' failed:\n%s\n%s\n" % (str(parameters), outp, outerr))
 
-class BaseSlimTestCase(BaseTestCase):    
-        
+class BaseSlimTestCase(BaseTestCase):
+
     def setUpGeneric(self, parameters, file):
-        proc = subprocess.Popen(["./osm2pgsql", "--slim", "-Sdefault.style", "-dosm2pgsql-test", "-C100"] + parameters + [file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        proc = subprocess.Popen([exe_path, "--slim", "-Sdefault.style", "-dosm2pgsql-test", "-C100"] + parameters + [file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         (outp, outerr) = proc.communicate()
         self.assertEqual (proc.returncode, 0, "Execution of osm2pgsql --slim with options: '%s' failed:\n%s\n%s\n" % (str(parameters), outp, outerr))
 
     def updateGeneric(self, parameters, file):
-        proc = subprocess.Popen(["./osm2pgsql", "--slim", "--append", "-Sdefault.style", "-dosm2pgsql-test", "-C100"] + parameters + [file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        proc = subprocess.Popen([exe_path, "--slim", "--append", "-Sdefault.style", "-dosm2pgsql-test", "-C100"] + parameters + [file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         (outp, outerr) = proc.communicate()
         self.assertEqual (proc.returncode, 0, "Execution of osm2pgsql --slim --append with options: '%s' failed:\n%s\n%s\n" % (str(parameters), outp, outerr))
-        
-class BaseGazetteerTestCase(BaseTestCase):    
-        
+
+class BaseGazetteerTestCase(BaseTestCase):
+
     def setUpGeneric(self, parameters, file):
-        proc = subprocess.Popen(["./osm2pgsql", "--slim", "-Ogazetteer", "-Sdefault.style", "-dosm2pgsql-test"] + parameters + [file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        proc = subprocess.Popen([exe_path, "--slim", "-Ogazetteer", "-Sdefault.style", "-dosm2pgsql-test"] + parameters + [file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         (outp, outerr) = proc.communicate()
         self.assertEqual (proc.returncode, 0, "Execution of osm2pgsql --slim gazetteer options: '%s' failed:\n%s\n%s\n" % (str(parameters), outp, outerr))
 
     def updateGeneric(self, parameters, file):
-        proc = subprocess.Popen(["./osm2pgsql", "--slim", "-Ogazetteer", "--append", "-Sdefault.style", "-dosm2pgsql-test"] + parameters + [file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        proc = subprocess.Popen([exe_path, "--slim", "-Ogazetteer", "--append", "-Sdefault.style", "-dosm2pgsql-test"] + parameters + [file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         (outp, outerr) = proc.communicate()
         self.assertEqual (proc.returncode, 0, "Execution of osm2pgsql --slim --append gazetteer options: '%s' failed:\n%s\n%s\n" % (str(parameters), outp, outerr))
-        
+
 
 #****************************************************************
 class BasicNonSlimTestCase(BaseNonSlimTestCase):
@@ -555,7 +556,7 @@ def setupDB():
             else:
                 print "The test needs a temporary tablespace to run in, but it does not exist. Please create the temporary tablespace. On Linux, you can do this by running:"
                 print "  sudo mkdir -p /tmp/psql-tablespace"
-                print "  sudo /bin/chown postgres.postgres tmp/psql-tablespace"
+                print "  sudo /bin/chown postgres.postgres /tmp/psql-tablespace"
                 print "  psql -c \"CREATE TABLESPACE tablespacetest LOCATION '/tmp/psql-tablespace'\" postgres"
                 exit(77)
         except Exception as e:
@@ -619,11 +620,15 @@ if __name__ == "__main__":
     parser.add_option("-f", dest="osm_file", action="store", metavar="FILE",
                       default=full_import_file,
                       help="Import a specific osm file [default=%default]")
+    parser.add_option("-x", dest="exe_path", action="store", metavar="FILE",
+                      default=exe_path,
+                      help="Use specified osm2pgsql executuable [default=%default]")
     (options, args) = parser.parse_args()
 
     if options.osm_file:
         full_import_file = options.osm_file
-
+    if options.exe_path:
+        exe_path = options.exe_path
 
 ts2 = CompleteTestSuite()
 success = False
diff --git a/tests/regression-test.sh b/tests/regression-test.sh
index b96f016..54042c3 100755
--- a/tests/regression-test.sh
+++ b/tests/regression-test.sh
@@ -1,5 +1,4 @@
 #!/usr/bin/env sh
 
-tests/regression-test.py -f tests/liechtenstein-2013-08-03.osm.pbf &&
-tests/regression-test.py -f tests/liechtenstein-2013-08-03.osm.bz2 &&
+tests/regression-test.py -f tests/liechtenstein-2013-08-03.osm.pbf
 echo "Tests passed :-)"
diff --git a/tests/test-expire-tiles.cpp b/tests/test-expire-tiles.cpp
index 258f6fe..82480bf 100644
--- a/tests/test-expire-tiles.cpp
+++ b/tests/test-expire-tiles.cpp
@@ -1,6 +1,7 @@
 #include "expire-tiles.hpp"
 #include "options.hpp"
 
+#include <iterator>
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
diff --git a/tests/test-hstore-match-only.cpp b/tests/test-hstore-match-only.cpp
new file mode 100644
index 0000000..e67d59c
--- /dev/null
+++ b/tests/test-hstore-match-only.cpp
@@ -0,0 +1,92 @@
+/*
+
+Test the hstore-match-only functionality of osm2pgsql in a hstore only database
+
+The tags of inteest are specified in hstore-match-only.style
+
+*/
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <cassert>
+#include <sstream>
+#include <stdexcept>
+#include <memory>
+
+#include "osmtypes.hpp"
+#include "osmdata.hpp"
+#include "middle.hpp"
+#include "output-pgsql.hpp"
+#include "options.hpp"
+#include "middle-pgsql.hpp"
+#include "middle-ram.hpp"
+#include "taginfo_impl.hpp"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include "tests/common.hpp"
+#include "tests/common-pg.hpp"
+
+int main(int argc, char *argv[]) {
+    std::unique_ptr<pg::tempdb> db;
+
+    try {
+        db.reset(new pg::tempdb);
+    } catch (const std::exception &e) {
+        std::cerr << "Unable to setup database: " << e.what() << "\n";
+        return 77; // <-- code to skip this test.
+    }
+
+    try {
+        std::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
+        options_t options;
+        options.database_options = db->database_options;
+        options.num_procs = 1;
+        options.prefix = "osm2pgsql_test";
+        options.style="tests/hstore-match-only.style";
+        options.hstore_match_only=1;
+        options.hstore_mode = HSTORE_NORM;
+        options.slim = 1;
+        options.append = false;
+
+        auto out_test = std::make_shared<output_pgsql_t>(mid_pgsql.get(), options);
+
+        osmdata_t osmdata(mid_pgsql, out_test);
+
+        testing::parse("tests/hstore-match-only.osm", "xml",
+                       options, &osmdata);
+
+        // tables should not contain any tag columns
+        db->check_count(4, "select count(column_name) from information_schema.columns where table_name='osm2pgsql_test_point'");
+        db->check_count(5, "select count(column_name) from information_schema.columns where table_name='osm2pgsql_test_polygon'");
+        db->check_count(5, "select count(column_name) from information_schema.columns where table_name='osm2pgsql_test_line'");
+        db->check_count(5, "select count(column_name) from information_schema.columns where table_name='osm2pgsql_test_roads'");
+
+        // the testfile contains 19 tagged ways and 7 tagged nodes
+        // out of them 18 ways and 6 nodes are interesting as specified by hstore-match-only.style
+        // as there is also one relation we should end up getting a database which contains:
+        // 6 objects in osm2pgsql_test_point
+        // 7 objects in osm2pgsql_test_polygon
+        // 12 objects in osm2pgsql_test_line
+        // 3 objects in osm2pgsql_test_roads
+
+        db->check_count(6, "select count(*) from osm2pgsql_test_point");
+        db->check_count(7, "select count(*) from osm2pgsql_test_polygon");
+        db->check_count(12, "select count(*) from osm2pgsql_test_line");
+        db->check_count(3, "select count(*) from osm2pgsql_test_roads");
+
+        return 0;
+
+    } catch (const std::exception &e) {
+        std::cerr << "ERROR: " << e.what() << std::endl;
+
+    } catch (...) {
+        std::cerr << "UNKNOWN ERROR" << std::endl;
+    }
+
+    return 1;
+}
diff --git a/tests/test-middle-flat.cpp b/tests/test-middle-flat.cpp
index bb9e45d..5a4be10 100644
--- a/tests/test-middle-flat.cpp
+++ b/tests/test-middle-flat.cpp
@@ -12,23 +12,23 @@
 #include "options.hpp"
 #include "middle-pgsql.hpp"
 
-#include <libpq-fe.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <boost/scoped_ptr.hpp>
-
 #include "tests/middle-tests.hpp"
 #include "tests/common-pg.hpp"
+#include "tests/common-cleanup.hpp"
+
+#define FLAT_NODES_FILE_NAME "tests/test_middle_flat.flat.nodes.bin"
 
 /* This is basically the same as test-middle-pgsql, but with flat nodes. */
 
 void run_tests(options_t options, const std::string cache_type) {
-  options.append = 0;
-  options.create = 1;
+  options.append = false;
+  options.create = true;
   options.flat_node_cache_enabled = true;
   // flat nodes truncates the file each time it's started, so we can reuse the same file
-  options.flat_node_file = boost::optional<std::string>("tests/test_middle_flat.flat.nodes.bin");
+  options.flat_node_file = boost::optional<std::string>(FLAT_NODES_FILE_NAME);
 
   {
     middle_pgsql_t mid_pgsql;
@@ -63,8 +63,8 @@ void run_tests(options_t options, const std::string cache_type) {
     mid_pgsql.commit();
     mid_pgsql.stop();
     // Switch to append mode because this tests updates
-    options.append = 1;
-    options.create = 0;
+    options.append = true;
+    options.create = false;
     mid_pgsql.start(&options);
     if (test_way_set(&mid_pgsql) != 0) { throw std::runtime_error("test_way_set failed."); }
 
@@ -73,7 +73,7 @@ void run_tests(options_t options, const std::string cache_type) {
   }*/
 }
 int main(int argc, char *argv[]) {
-  boost::scoped_ptr<pg::tempdb> db;
+  std::unique_ptr<pg::tempdb> db;
 
   try {
     db.reset(new pg::tempdb);
@@ -84,12 +84,16 @@ int main(int argc, char *argv[]) {
 
   try {
     options_t options;
-    options.conninfo = db->conninfo().c_str();
+    options.database_options = db->database_options;
     options.scale = 10000000;
     options.cache = 1;
     options.num_procs = 1;
     options.prefix = "osm2pgsql_test";
-    options.slim = 1;
+    options.slim = true;
+
+    // remove flat nodes file  on exit - it's 20GB and bad manners to
+    // leave that lying around on the filesystem.
+    cleanup::file flat_nodes_file(FLAT_NODES_FILE_NAME);
 
     options.alloc_chunkwise = ALLOC_SPARSE | ALLOC_DENSE; // what you get with optimized
     run_tests(options, "optimized");
@@ -101,6 +105,7 @@ int main(int argc, char *argv[]) {
 
     options.alloc_chunkwise = ALLOC_DENSE | ALLOC_DENSE_CHUNK; // what you get with chunk
     run_tests(options, "chunk");
+
   } catch (const std::exception &e) {
     std::cerr << "ERROR: " << e.what() << std::endl;
     return 1;
diff --git a/tests/test-middle-pgsql.cpp b/tests/test-middle-pgsql.cpp
index 191f81d..a22af1a 100644
--- a/tests/test-middle-pgsql.cpp
+++ b/tests/test-middle-pgsql.cpp
@@ -12,18 +12,15 @@
 #include "options.hpp"
 #include "middle-pgsql.hpp"
 
-#include <libpq-fe.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <boost/scoped_ptr.hpp>
-
 #include "tests/middle-tests.hpp"
 #include "tests/common-pg.hpp"
 
 void run_tests(options_t options, const std::string cache_type) {
-  options.append = 0;
-  options.create = 1;
+  options.append = false;
+  options.create = true;
   {
     middle_pgsql_t mid_pgsql;
     output_null_t out_test(&mid_pgsql, options);
@@ -54,8 +51,8 @@ void run_tests(options_t options, const std::string cache_type) {
     mid_pgsql.commit();
     mid_pgsql.stop();
     // Switch to append mode because this tests updates
-    options.append = 1;
-    options.create = 0;
+    options.append = true;
+    options.create = false;
     mid_pgsql.start(&options);
     if (test_way_set(&mid_pgsql) != 0) { throw std::runtime_error("test_way_set failed."); }
 
@@ -64,7 +61,7 @@ void run_tests(options_t options, const std::string cache_type) {
   }
 }
 int main(int argc, char *argv[]) {
-  boost::scoped_ptr<pg::tempdb> db;
+  std::unique_ptr<pg::tempdb> db;
 
   try {
     db.reset(new pg::tempdb);
@@ -75,12 +72,12 @@ int main(int argc, char *argv[]) {
 
   try {
     options_t options;
-    options.conninfo = db->conninfo().c_str();
+    options.database_options = db->database_options;
     options.scale = 10000000;
     options.cache = 1;
     options.num_procs = 1;
     options.prefix = "osm2pgsql_test";
-    options.slim = 1;
+    options.slim = true;
 
     options.alloc_chunkwise = ALLOC_SPARSE | ALLOC_DENSE; // what you get with optimized
     run_tests(options, "optimized");
diff --git a/tests/test-options-database.cpp b/tests/test-options-database.cpp
new file mode 100644
index 0000000..f0e65ea
--- /dev/null
+++ b/tests/test-options-database.cpp
@@ -0,0 +1,87 @@
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sstream>
+#include <stdexcept>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <boost/format.hpp>
+
+#include <options.hpp>
+
+namespace {
+
+struct skip_test : public std::exception {
+    const char *what() const noexcept { return "Test skipped."; }
+};
+
+void run_test(const char* test_name, void (*testfunc)()) {
+    try {
+        fprintf(stderr, "%s\n", test_name);
+        testfunc();
+
+    } catch (const skip_test &) {
+        exit(77); // <-- code to skip this test.
+
+    } catch (const std::exception& e) {
+        fprintf(stderr, "%s\n", e.what());
+        fprintf(stderr, "FAIL\n");
+        exit(EXIT_FAILURE);
+    }
+
+    fprintf(stderr, "PASS\n");
+}
+#define RUN_TEST(x) run_test(#x, &(x))
+
+void expect_conninfo(const database_options_t &db, const std::string &expect) {
+    if (db.conninfo() != expect) {
+        throw std::runtime_error((boost::format("Expected connection info of %1%, got %2%.") % expect % db.conninfo()).str());
+    }
+}
+
+/**
+ * Tests that the conninfo strings are appropriately generated
+ * This test is stricter than it needs to be, as it also cares about order,
+ * but the current implementation always uses the same order, and attempting to
+ * parse a conninfo string is complex.
+ */
+void test_conninfo() {
+    database_options_t db;
+    expect_conninfo(db, "dbname='gis'");
+    db.db = "foo";
+    expect_conninfo(db, "dbname='foo'");
+
+    db = database_options_t();
+    db.username = "bar";
+    expect_conninfo(db, "dbname='gis' user='bar'");
+
+    db = database_options_t();
+    db.password = "bar";
+    expect_conninfo(db, "dbname='gis' password='bar'");
+
+    db = database_options_t();
+    db.host = "bar";
+    expect_conninfo(db, "dbname='gis' host='bar'");
+
+    db = database_options_t();
+    db.port = "bar";
+    expect_conninfo(db, "dbname='gis' port='bar'");
+
+    db = database_options_t();
+    db.db = "foo";
+    db.username = "bar";
+    db.password = "baz";
+    db.host = "bzz";
+    db.port = "123";
+    expect_conninfo(db, "dbname='foo' user='bar' password='baz' host='bzz' port='123'");
+}
+
+} // anonymous namespace
+
+int main(int argc, char *argv[]) {
+    RUN_TEST(test_conninfo);
+
+    return 0;
+}
diff --git a/tests/test-parse-options.cpp b/tests/test-options-parse.cpp
similarity index 79%
rename from tests/test-parse-options.cpp
rename to tests/test-options-parse.cpp
index 2efb23e..3b280c5 100644
--- a/tests/test-parse-options.cpp
+++ b/tests/test-options-parse.cpp
@@ -37,7 +37,7 @@ void parse_fail(const int argc, const char* argv[], const std::string& fail_mess
 {
     try
     {
-        options_t options = options_t::parse(argc, const_cast<char **>(argv));
+        options_t options = options_t(argc, const_cast<char **>(argv));
         throw std::logic_error((boost::format("Expected '%1%'") % fail_message).str());
     }
     catch(const std::runtime_error& e)
@@ -68,17 +68,17 @@ void test_incompatible_args()
 void test_middles()
 {
     const char* a1[] = {"osm2pgsql", "--slim", "tests/liechtenstein-2013-08-03.osm.pbf"};
-    options_t options = options_t::parse(len(a1), const_cast<char **>(a1));
-    boost::shared_ptr<middle_t> mid = middle_t::create_middle(options.slim);
-    if(dynamic_cast<middle_pgsql_t *>(mid.get()) == NULL)
+    options_t options = options_t(len(a1), const_cast<char **>(a1));
+    std::shared_ptr<middle_t> mid = middle_t::create_middle(options.slim);
+    if(dynamic_cast<middle_pgsql_t *>(mid.get()) == nullptr)
     {
         throw std::logic_error("Using slim mode we expected a pgsql middle");
     }
 
     const char* a2[] = {"osm2pgsql", "tests/liechtenstein-2013-08-03.osm.pbf"};
-    options = options_t::parse(len(a2), const_cast<char **>(a2));
+    options = options_t(len(a2), const_cast<char **>(a2));
     mid = middle_t::create_middle(options.slim);
-    if(dynamic_cast<middle_ram_t *>(mid.get()) == NULL)
+    if(dynamic_cast<middle_ram_t *>(mid.get()) == nullptr)
     {
         throw std::logic_error("Using without slim mode we expected a ram middle");
     }
@@ -87,37 +87,37 @@ void test_middles()
 void test_outputs()
 {
     const char* a1[] = {"osm2pgsql", "-O", "pgsql", "--style", "default.style", "tests/liechtenstein-2013-08-03.osm.pbf"};
-    options_t options = options_t::parse(len(a1), const_cast<char **>(a1));
-    boost::shared_ptr<middle_t> mid = middle_t::create_middle(options.slim);
-    std::vector<boost::shared_ptr<output_t> > outs = output_t::create_outputs(mid.get(), options);
+    options_t options = options_t(len(a1), const_cast<char **>(a1));
+    std::shared_ptr<middle_t> mid = middle_t::create_middle(options.slim);
+    std::vector<std::shared_ptr<output_t> > outs = output_t::create_outputs(mid.get(), options);
     output_t* out = outs.front().get();
-    if(dynamic_cast<output_pgsql_t *>(out) == NULL)
+    if(dynamic_cast<output_pgsql_t *>(out) == nullptr)
     {
         throw std::logic_error("Expected a pgsql output");
     }
 
     const char* a2[] = {"osm2pgsql", "-O", "gazetteer", "--style", "default.style", "tests/liechtenstein-2013-08-03.osm.pbf"};
-    options = options_t::parse(len(a2), const_cast<char **>(a2));
+    options = options_t(len(a2), const_cast<char **>(a2));
     mid = middle_t::create_middle(options.slim);
     outs = output_t::create_outputs(mid.get(), options);
     out = outs.front().get();
-    if(dynamic_cast<output_gazetteer_t *>(out) == NULL)
+    if(dynamic_cast<output_gazetteer_t *>(out) == nullptr)
     {
         throw std::logic_error("Expected a gazetteer output");
     }
 
     const char* a3[] = {"osm2pgsql", "-O", "null", "--style", "default.style", "tests/liechtenstein-2013-08-03.osm.pbf"};
-    options = options_t::parse(len(a3), const_cast<char **>(a3));
+    options = options_t(len(a3), const_cast<char **>(a3));
     mid = middle_t::create_middle(options.slim);
     outs = output_t::create_outputs(mid.get(), options);
     out = outs.front().get();
-    if(dynamic_cast<output_null_t *>(out) == NULL)
+    if(dynamic_cast<output_null_t *>(out) == nullptr)
     {
         throw std::logic_error("Expected a null output");
     }
 
     const char* a4[] = {"osm2pgsql", "-O", "keine_richtige_ausgabe", "--style", "default.style", "tests/liechtenstein-2013-08-03.osm.pbf"};
-    options = options_t::parse(len(a4), const_cast<char **>(a4));
+    options = options_t(len(a4), const_cast<char **>(a4));
     mid = middle_t::create_middle(options.slim);
     try
     {
@@ -134,21 +134,21 @@ void test_outputs()
 
 int get_random_proj(std::vector<std::string>& args)
 {
-    int proj = rand() % (PROJ_COUNT + 1);
+    int proj = rand() % 3;
     switch(proj)
     {
-    case PROJ_LATLONG:
-    case PROJ_SPHERE_MERC:
-        args.push_back(reprojection(proj).project_getprojinfo()->option);
-        break;
-    default:
-        args.push_back("--proj");
-        //nice contiguous block of valid epsgs here randomly use one of those..
-        proj = (rand() % (2962 - 2308)) + 2308;
-        args.push_back((boost::format("%1%") % proj).str());
-        proj = -proj;
-        break;
+        case 1:
+            args.push_back("-l");
+            return PROJ_LATLONG;
+        case 2:
+            args.push_back("-m");
+            return PROJ_SPHERE_MERC;
     }
+
+    args.push_back("--proj");
+    //nice contiguous block of valid epsgs here randomly use one of those..
+    proj = (rand() % (2962 - 2308)) + 2308;
+    args.push_back((boost::format("%1%") % proj).str());
     return proj;
 }
 
@@ -206,7 +206,7 @@ void test_random_perms()
         args.push_back("osm2pgsql");
 
         //pick a projection
-        options.projection.reset(new reprojection(get_random_proj(args)));
+        options.projection.reset(reprojection::create_projection(get_random_proj(args)));
 
         //pick a style file
         std::string style = get_random_string(15);
@@ -215,12 +215,12 @@ void test_random_perms()
         args.push_back(style);
 
         add_arg_and_val_or_not("--cache", args, options.cache, rand() % 800);
-        add_arg_and_val_or_not("--database", args, options.db.c_str(), get_random_string(6));
-        if (options.username) {
-            add_arg_and_val_or_not("--username", args, options.username->c_str(), get_random_string(6));
+        add_arg_and_val_or_not("--database", args, options.database_options.db.c_str(), get_random_string(6));
+        if (options.database_options.username) {
+            add_arg_and_val_or_not("--username", args, options.database_options.username->c_str(), get_random_string(6));
         }
-        if (options.host) {
-            add_arg_and_val_or_not("--host", args, options.host->c_str(), get_random_string(6));
+        if (options.database_options.host) {
+            add_arg_and_val_or_not("--host", args, options.database_options.host->c_str(), get_random_string(6));
         }
         //add_arg_and_val_or_not("--port", args, options.port, rand() % 9999);
 
@@ -228,7 +228,6 @@ void test_random_perms()
         //--hstore-column   Add an additional hstore (key/value) column containing all tags that start with the specified string, eg --hstore-column "name:" will produce an extra hstore column that contains all name:xx tags
 
         add_arg_or_not("--hstore-add-index", args, options.enable_hstore_index);
-        add_arg_or_not("--utf8-sanitize", args, options.sanitize);
 
         //--tablespace-index    The name of the PostgreSQL tablespace where all indexes will be created. The following options allow more fine-grained control:
         //      --tablespace-main-data    tablespace for main tables
@@ -258,7 +257,7 @@ void test_random_perms()
 
         add_arg_and_val_or_not("--prefix", args, options.prefix.c_str(), get_random_string(15));
 
-        //--input-reader    Input frontend. libxml2   - Parse XML using libxml2. (default) primitive - Primitive XML parsing. pbf       - OSM binary format.
+        //--input-reader    Input frontend. auto, o5m, xml, pbf
 
         if (options.tag_transform_script) {
             add_arg_and_val_or_not("--tag-transform-script", args, options.tag_transform_script->c_str(), get_random_string(15));
@@ -272,10 +271,10 @@ void test_random_perms()
         args.push_back("tests/liechtenstein-2013-08-03.osm.pbf");
 
         const char** argv = new const char*[args.size() + 1];
-        argv[args.size()] = NULL;
+        argv[args.size()] = nullptr;
         for(std::vector<std::string>::const_iterator arg = args.begin(); arg != args.end(); ++arg)
             argv[arg - args.begin()] = arg->c_str();
-        options_t::parse(args.size(), const_cast<char **>(argv));
+        options_t((int) args.size(), const_cast<char **>(argv));
         delete[] argv;
     }
 }
diff --git a/tests/test-output-multi-line-storage.cpp b/tests/test-output-multi-line-storage.cpp
index 41541a0..53c35d3 100644
--- a/tests/test-output-multi-line-storage.cpp
+++ b/tests/test-output-multi-line-storage.cpp
@@ -13,41 +13,18 @@
 #include "output-multi.hpp"
 #include "options.hpp"
 #include "taginfo_impl.hpp"
-#include "parse.hpp"
 
-#include <libpq-fe.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <boost/scoped_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 
 #include "tests/middle-tests.hpp"
 #include "tests/common-pg.hpp"
-
-void check_count(pg::conn_ptr &conn, int expected, const std::string &query) {
-    pg::result_ptr res = conn->exec(query);
-
-    int ntuples = PQntuples(res->get());
-    if (ntuples != 1) {
-        throw std::runtime_error((boost::format("Expected only one tuple from a query "
-                                                "to check COUNT(*), but got %1%. Query "
-                                                "was: %2%.")
-                                  % ntuples % query).str());
-    }
-
-    std::string numstr = PQgetvalue(res->get(), 0, 0);
-    int count = boost::lexical_cast<int>(numstr);
-
-    if (count != expected) {
-        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
-                                                "query: %3%.")
-                                  % expected % count % query).str());
-    }
-}
+#include "tests/common.hpp"
 
 int main(int argc, char *argv[]) {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::unique_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -58,47 +35,36 @@ int main(int argc, char *argv[]) {
 
     try {
         options_t options;
-        options.conninfo = db->conninfo().c_str();
+        options.database_options = db->database_options;
         options.num_procs = 1;
-        options.slim = 1;
+        options.slim = true;
 
-        options.projection.reset(new reprojection(PROJ_LATLONG));
+        options.projection.reset(reprojection::create_projection(PROJ_LATLONG));
 
         options.output_backend = "multi";
         options.style = "tests/test_output_multi_line_trivial.style.json";
 
-        //setup the front (input)
-        parse_delegate_t parser(options.extra_attributes, options.bbox, options.projection);
-
         //setup the middle
-        boost::shared_ptr<middle_t> middle = middle_t::create_middle(options.slim);
+        std::shared_ptr<middle_t> middle = middle_t::create_middle(options.slim);
 
         //setup the backend (output)
-        std::vector<boost::shared_ptr<output_t> > outputs = output_t::create_outputs(middle.get(), options);
+        std::vector<std::shared_ptr<output_t> > outputs = output_t::create_outputs(middle.get(), options);
 
         //let osmdata orchestrate between the middle and the outs
         osmdata_t osmdata(middle, outputs);
 
-        osmdata.start();
-
-        if (parser.streamFile("libxml2", "tests/test_output_multi_line_storage.osm", options.sanitize, &osmdata) != 0) {
-            throw std::runtime_error("Unable to read input file `tests/test_output_multi_line_storage.osm'.");
-        }
-
-        osmdata.stop();
-
-        // start a new connection to run tests on
-        pg::conn_ptr test_conn = pg::conn::connect(db->conninfo());
+        testing::parse("tests/test_output_multi_line_storage.osm", "xml",
+                       options, &osmdata);
 
-        check_count(test_conn, 1, "select count(*) from pg_catalog.pg_class where relname = 'test_line'");
-        check_count(test_conn, 3, "select count(*) from test_line");
+        db->check_count(1, "select count(*) from pg_catalog.pg_class where relname = 'test_line'");
+        db->check_count(3, "select count(*) from test_line");
 
         //check that we have the number of vertexes in each linestring
-        check_count(test_conn, 3, "SELECT ST_NumPoints(way) FROM test_line WHERE osm_id = 1");
-        check_count(test_conn, 2, "SELECT ST_NumPoints(way) FROM test_line WHERE osm_id = 2");
-        check_count(test_conn, 2, "SELECT ST_NumPoints(way) FROM test_line WHERE osm_id = 3");
+        db->check_count(3, "SELECT ST_NumPoints(way) FROM test_line WHERE osm_id = 1");
+        db->check_count(2, "SELECT ST_NumPoints(way) FROM test_line WHERE osm_id = 2");
+        db->check_count(2, "SELECT ST_NumPoints(way) FROM test_line WHERE osm_id = 3");
 
-        check_count(test_conn, 3, "SELECT COUNT(*) FROM test_line WHERE foo = 'bar'");
+        db->check_count(3, "SELECT COUNT(*) FROM test_line WHERE foo = 'bar'");
         return 0;
 
     } catch (const std::exception &e) {
diff --git a/tests/test-output-multi-line.cpp b/tests/test-output-multi-line.cpp
index fe6b60b..d904200 100644
--- a/tests/test-output-multi-line.cpp
+++ b/tests/test-output-multi-line.cpp
@@ -13,41 +13,18 @@
 #include "options.hpp"
 #include "middle-pgsql.hpp"
 #include "taginfo_impl.hpp"
-#include "parse.hpp"
 
-#include <libpq-fe.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <boost/scoped_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 
 #include "tests/middle-tests.hpp"
 #include "tests/common-pg.hpp"
-
-void check_count(pg::conn_ptr &conn, int expected, const std::string &query) {
-    pg::result_ptr res = conn->exec(query);
-
-    int ntuples = PQntuples(res->get());
-    if (ntuples != 1) {
-        throw std::runtime_error((boost::format("Expected only one tuple from a query "
-                                                "to check COUNT(*), but got %1%. Query "
-                                                "was: %2%.")
-                                  % ntuples % query).str());
-    }
-
-    std::string numstr = PQgetvalue(res->get(), 0, 0);
-    int count = boost::lexical_cast<int>(numstr);
-
-    if (count != expected) {
-        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
-                                                "query: %3%.")
-                                  % expected % count % query).str());
-    }
-}
+#include "tests/common.hpp"
 
 int main(int argc, char *argv[]) {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::unique_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -57,58 +34,48 @@ int main(int argc, char *argv[]) {
     }
 
     try {
-        boost::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
+        std::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
         options_t options;
-        options.conninfo = db->conninfo().c_str();
+        options.database_options = db->database_options;
         options.num_procs = 1;
-        options.slim = 1;
+        options.slim = true;
 
-        boost::shared_ptr<geometry_processor> processor =
+        std::shared_ptr<geometry_processor> processor =
             geometry_processor::create("line", &options);
 
         export_list columns;
         { taginfo info; info.name = "highway"; info.type = "text"; columns.add(OSMTYPE_WAY, info); }
 
-        boost::shared_ptr<output_multi_t> out_test(new output_multi_t("foobar_highways", processor, columns, mid_pgsql.get(), options));
+        // This actually uses the multi-backend with C transforms, not Lua transforms. This is unusual and doesn't reflect real practice
+        auto out_test = std::make_shared<output_multi_t>("foobar_highways", processor, columns, mid_pgsql.get(), options);
 
         osmdata_t osmdata(mid_pgsql, out_test);
 
-        boost::scoped_ptr<parse_delegate_t> parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection));
-
-        osmdata.start();
-
-        if (parser->streamFile("pbf", "tests/liechtenstein-2013-08-03.osm.pbf", options.sanitize, &osmdata) != 0) {
-            throw std::runtime_error("Unable to read input file `tests/liechtenstein-2013-08-03.osm.pbf'.");
-        }
-
-        parser.reset(NULL);
-
-        osmdata.stop();
+        testing::parse("tests/liechtenstein-2013-08-03.osm.pbf", "pbf",
+                       options, &osmdata);
 
         // start a new connection to run tests on
-        pg::conn_ptr test_conn = pg::conn::connect(db->conninfo());
-
-        check_count(test_conn, 1, "select count(*) from pg_catalog.pg_class where relname = 'foobar_highways'");
-        check_count(test_conn, 2753, "select count(*) from foobar_highways");
+        db->check_count(1, "select count(*) from pg_catalog.pg_class where relname = 'foobar_highways'");
+        db->check_count(2752, "select count(*) from foobar_highways");
 
         //check that we have the right spread
-        check_count(test_conn, 13, "select count(*) from foobar_highways where highway='bridleway'");
-        check_count(test_conn, 3, "select count(*) from foobar_highways where highway='construction'");
-        check_count(test_conn, 96, "select count(*) from foobar_highways where highway='cycleway'");
-        check_count(test_conn, 249, "select count(*) from foobar_highways where highway='footway'");
-        check_count(test_conn, 18, "select count(*) from foobar_highways where highway='living_street'");
-        check_count(test_conn, 171, "select count(*) from foobar_highways where highway='path'");
-        check_count(test_conn, 6, "select count(*) from foobar_highways where highway='pedestrian'");
-        check_count(test_conn, 81, "select count(*) from foobar_highways where highway='primary'");
-        check_count(test_conn, 842, "select count(*) from foobar_highways where highway='residential'");
-        check_count(test_conn, 3, "select count(*) from foobar_highways where highway='road'");
-        check_count(test_conn, 90, "select count(*) from foobar_highways where highway='secondary'");
-        check_count(test_conn, 1, "select count(*) from foobar_highways where highway='secondary_link'");
-        check_count(test_conn, 352, "select count(*) from foobar_highways where highway='service'");
-        check_count(test_conn, 34, "select count(*) from foobar_highways where highway='steps'");
-        check_count(test_conn, 33, "select count(*) from foobar_highways where highway='tertiary'");
-        check_count(test_conn, 597, "select count(*) from foobar_highways where highway='track'");
-        check_count(test_conn, 164, "select count(*) from foobar_highways where highway='unclassified'");
+        db->check_count(13, "select count(*) from foobar_highways where highway='bridleway'");
+        db->check_count(3, "select count(*) from foobar_highways where highway='construction'");
+        db->check_count(96, "select count(*) from foobar_highways where highway='cycleway'");
+        db->check_count(249, "select count(*) from foobar_highways where highway='footway'");
+        db->check_count(18, "select count(*) from foobar_highways where highway='living_street'");
+        db->check_count(171, "select count(*) from foobar_highways where highway='path'");
+        db->check_count(5, "select count(*) from foobar_highways where highway='pedestrian'");
+        db->check_count(81, "select count(*) from foobar_highways where highway='primary'");
+        db->check_count(842, "select count(*) from foobar_highways where highway='residential'");
+        db->check_count(3, "select count(*) from foobar_highways where highway='road'");
+        db->check_count(90, "select count(*) from foobar_highways where highway='secondary'");
+        db->check_count(1, "select count(*) from foobar_highways where highway='secondary_link'");
+        db->check_count(352, "select count(*) from foobar_highways where highway='service'");
+        db->check_count(34, "select count(*) from foobar_highways where highway='steps'");
+        db->check_count(33, "select count(*) from foobar_highways where highway='tertiary'");
+        db->check_count(597, "select count(*) from foobar_highways where highway='track'");
+        db->check_count(164, "select count(*) from foobar_highways where highway='unclassified'");
         return 0;
 
     } catch (const std::exception &e) {
diff --git a/tests/test-output-multi-point-multi-table.cpp b/tests/test-output-multi-point-multi-table.cpp
index f76c147..43c47f0 100644
--- a/tests/test-output-multi-point-multi-table.cpp
+++ b/tests/test-output-multi-point-multi-table.cpp
@@ -13,46 +13,18 @@
 #include "options.hpp"
 #include "middle-pgsql.hpp"
 #include "taginfo_impl.hpp"
-#include "parse.hpp"
 
-#include <libpq-fe.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <boost/scoped_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 
 #include "tests/middle-tests.hpp"
 #include "tests/common-pg.hpp"
-
-void check_count(pg::conn_ptr &conn, int expected, const std::string &query) {
-    pg::result_ptr res = conn->exec(query);
-
-    if (PQresultStatus(res->get()) != PGRES_TUPLES_OK) {
-        throw std::runtime_error((boost::format("Query ERROR running %1%: %2%")
-                                  % query % PQresultErrorMessage(res->get())).str());
-    }
-
-    int ntuples = PQntuples(res->get());
-    if (ntuples != 1) {
-        throw std::runtime_error((boost::format("Expected only one tuple from a query "
-                                                "to check COUNT(*), but got %1%. Query "
-                                                "was: %2%.")
-                                  % ntuples % query).str());
-    }
-
-    std::string numstr = PQgetvalue(res->get(), 0, 0);
-    int count = boost::lexical_cast<int>(numstr);
-
-    if (count != expected) {
-        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
-                                                "query: %3%.")
-                                  % expected % count % query).str());
-    }
-}
+#include "tests/common.hpp"
 
 int main(int argc, char *argv[]) {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::unique_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -62,70 +34,58 @@ int main(int argc, char *argv[]) {
     }
 
     try {
-        boost::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
+        std::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
         options_t options;
-        options.conninfo = db->conninfo().c_str();
+        options.database_options = db->database_options;
         options.num_procs = 1;
         options.prefix = "osm2pgsql_test";
-        options.slim = 1;
+        options.slim = true;
 
         export_list columns;
         { taginfo info; info.name = "amenity"; info.type = "text"; columns.add(OSMTYPE_NODE, info); }
 
-        std::vector<boost::shared_ptr<output_t> > outputs;
+        std::vector<std::shared_ptr<output_t> > outputs;
 
         // let's make lots of tables!
         for (int i = 0; i < 10; ++i) {
             std::string name = (boost::format("foobar_%d") % i).str();
 
-            boost::shared_ptr<geometry_processor> processor =
+            std::shared_ptr<geometry_processor> processor =
                 geometry_processor::create("point", &options);
 
-            boost::shared_ptr<output_multi_t> out_test(new output_multi_t(name, processor, columns, mid_pgsql.get(), options));
+            auto out_test = std::make_shared<output_multi_t>(name, processor, columns, mid_pgsql.get(), options);
 
             outputs.push_back(out_test);
         }
 
         osmdata_t osmdata(mid_pgsql, outputs);
 
-        boost::scoped_ptr<parse_delegate_t> parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection));
-
-        osmdata.start();
-
-        if (parser->streamFile("pbf", "tests/liechtenstein-2013-08-03.osm.pbf", options.sanitize, &osmdata) != 0) {
-            throw std::runtime_error("Unable to read input file `tests/liechtenstein-2013-08-03.osm.pbf'.");
-        }
-
-        parser.reset(NULL);
-
-        osmdata.stop();
-
-        // start a new connection to run tests on
-        pg::conn_ptr test_conn = pg::conn::connect(db->conninfo());
+        testing::parse("tests/liechtenstein-2013-08-03.osm.pbf", "pbf",
+                       options, &osmdata);
 
         for (int i = 0; i < 10; ++i) {
             std::string name = (boost::format("foobar_%d") % i).str();
 
-            check_count(test_conn, 1,
+            db->check_count(1,
                         (boost::format("select count(*) from pg_catalog.pg_class "
                                        "where relname = 'foobar_%d'")
                          % i).str());
 
-            check_count(test_conn, 244,
+            db->check_count(244,
                         (boost::format("select count(*) from foobar_%d")
                          % i).str());
 
-            check_count(test_conn, 36,
+            db->check_count(36,
                         (boost::format("select count(*) from foobar_%d "
                                        "where amenity='parking'")
                          % i).str());
 
-            check_count(test_conn, 34,
+            db->check_count(34,
                         (boost::format("select count(*) from foobar_%d "
                                        "where amenity='bench'")
                          % i).str());
 
-            check_count(test_conn, 1,
+            db->check_count(1,
                         (boost::format("select count(*) from foobar_%d "
                                        "where amenity='vending_machine'")
                          % i).str());
diff --git a/tests/test-output-multi-point.cpp b/tests/test-output-multi-point.cpp
index fe29481..e5490d7 100644
--- a/tests/test-output-multi-point.cpp
+++ b/tests/test-output-multi-point.cpp
@@ -13,41 +13,18 @@
 #include "options.hpp"
 #include "middle-pgsql.hpp"
 #include "taginfo_impl.hpp"
-#include "parse.hpp"
 
-#include <libpq-fe.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <boost/scoped_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 
 #include "tests/middle-tests.hpp"
 #include "tests/common-pg.hpp"
-
-void check_count(pg::conn_ptr &conn, int expected, const std::string &query) {
-    pg::result_ptr res = conn->exec(query);
-
-    int ntuples = PQntuples(res->get());
-    if (ntuples != 1) {
-        throw std::runtime_error((boost::format("Expected only one tuple from a query "
-                                                "to check COUNT(*), but got %1%. Query "
-                                                "was: %2%.")
-                                  % ntuples % query).str());
-    }
-
-    std::string numstr = PQgetvalue(res->get(), 0, 0);
-    int count = boost::lexical_cast<int>(numstr);
-
-    if (count != expected) {
-        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
-                                                "query: %3%.")
-                                  % expected % count % query).str());
-    }
-}
+#include "tests/common.hpp"
 
 int main(int argc, char *argv[]) {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::unique_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -57,52 +34,43 @@ int main(int argc, char *argv[]) {
     }
 
     try {
-        boost::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
+        std::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
         options_t options;
-        options.conninfo = db->conninfo().c_str();
+        options.database_options = db->database_options;
         options.num_procs = 1;
         options.prefix = "osm2pgsql_test";
-        options.slim = 1;
+        options.slim = true;
 
-        boost::shared_ptr<geometry_processor> processor =
+        std::shared_ptr<geometry_processor> processor =
             geometry_processor::create("point", &options);
 
         export_list columns;
         { taginfo info; info.name = "amenity"; info.type = "text"; columns.add(OSMTYPE_NODE, info); }
 
-        boost::shared_ptr<output_multi_t> out_test(new output_multi_t("foobar_amenities", processor, columns, mid_pgsql.get(), options));
+        auto out_test = std::make_shared<output_multi_t>("foobar_amenities", processor, columns, mid_pgsql.get(), options);
 
         osmdata_t osmdata(mid_pgsql, out_test);
 
-        boost::scoped_ptr<parse_delegate_t> parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection));
-
-        osmdata.start();
-
-        if (parser->streamFile("pbf", "tests/liechtenstein-2013-08-03.osm.pbf", options.sanitize, &osmdata) != 0) {
-            throw std::runtime_error("Unable to read input file `tests/liechtenstein-2013-08-03.osm.pbf'.");
-        }
-
-        parser.reset(NULL);
-
-        osmdata.stop();
+        testing::parse("tests/liechtenstein-2013-08-03.osm.pbf", "pbf",
+                       options, &osmdata);
 
         // start a new connection to run tests on
-        pg::conn_ptr test_conn = pg::conn::connect(db->conninfo());
+        pg::conn_ptr test_conn = pg::conn::connect(db->database_options);
 
-        check_count(test_conn, 1,
+        db->check_count(1,
                     "select count(*) from pg_catalog.pg_class "
                     "where relname = 'foobar_amenities'");
 
-        check_count(test_conn, 244,
+        db->check_count(244,
                     "select count(*) from foobar_amenities");
 
-        check_count(test_conn, 36,
+        db->check_count(36,
                     "select count(*) from foobar_amenities where amenity='parking'");
 
-        check_count(test_conn, 34,
+        db->check_count(34,
                     "select count(*) from foobar_amenities where amenity='bench'");
 
-        check_count(test_conn, 1,
+        db->check_count(1,
                     "select count(*) from foobar_amenities where amenity='vending_machine'");
 
         return 0;
diff --git a/tests/test-output-multi-poly-trivial.cpp b/tests/test-output-multi-poly-trivial.cpp
index 611ff36..e1ade0b 100644
--- a/tests/test-output-multi-poly-trivial.cpp
+++ b/tests/test-output-multi-poly-trivial.cpp
@@ -13,106 +13,72 @@
 #include "output-multi.hpp"
 #include "options.hpp"
 #include "taginfo_impl.hpp"
-#include "parse.hpp"
 
-#include <libpq-fe.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <boost/scoped_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 
 #include "tests/middle-tests.hpp"
 #include "tests/common-pg.hpp"
-
-void check_count(pg::conn_ptr &conn, int expected, const std::string &query) {
-    pg::result_ptr res = conn->exec(query);
-
-    int ntuples = PQntuples(res->get());
-    if (ntuples != 1) {
-        throw std::runtime_error((boost::format("Expected only one tuple from a query "
-                                                "to check COUNT(*), but got %1%. Query "
-                                                "was: %2%.")
-                                  % ntuples % query).str());
-    }
-
-    std::string numstr = PQgetvalue(res->get(), 0, 0);
-    int count = boost::lexical_cast<int>(numstr);
-
-    if (count != expected) {
-        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
-                                                "query: %3%.")
-                                  % expected % count % query).str());
-    }
-}
+#include "tests/common.hpp"
 
 void run_osm2pgsql(options_t &options) {
-  //setup the front (input)
-  parse_delegate_t parser(options.extra_attributes, options.bbox, options.projection);
-
   //setup the middle
-  boost::shared_ptr<middle_t> middle = middle_t::create_middle(options.slim);
+  std::shared_ptr<middle_t> middle = middle_t::create_middle(options.slim);
 
   //setup the backend (output)
-  std::vector<boost::shared_ptr<output_t> > outputs = output_t::create_outputs(middle.get(), options);
+  std::vector<std::shared_ptr<output_t> > outputs = output_t::create_outputs(middle.get(), options);
 
   //let osmdata orchestrate between the middle and the outs
   osmdata_t osmdata(middle, outputs);
 
-  osmdata.start();
-
-  if (parser.streamFile("libxml2", "tests/test_output_multi_poly_trivial.osm", options.sanitize, &osmdata) != 0) {
-    throw std::runtime_error("Unable to read input file `tests/test_output_multi_poly_trivial.osm'.");
-  }
-
-  osmdata.stop();
+  testing::parse("tests/test_output_multi_poly_trivial.osm", "xml",
+                 options, &osmdata);
 }
 
-void check_output_poly_trivial(int enable_multi, std::string conninfo) {
+void check_output_poly_trivial(bool enable_multi, std::shared_ptr<pg::tempdb> db) {
   options_t options;
-  options.conninfo = conninfo.c_str();
+  options.database_options = db->database_options;
   options.num_procs = 1;
   options.slim = 1;
   options.enable_multi = enable_multi;
 
-  options.projection.reset(new reprojection(PROJ_LATLONG));
+  options.projection.reset(reprojection::create_projection(PROJ_LATLONG));
 
   options.output_backend = "multi";
   options.style = "tests/test_output_multi_poly_trivial.style.json";
 
   run_osm2pgsql(options);
 
-  // start a new connection to run tests on
-  pg::conn_ptr test_conn = pg::conn::connect(conninfo);
-
   // expect that the table exists
-  check_count(test_conn, 1, "select count(*) from pg_catalog.pg_class where relname = 'test_poly'");
+  db->check_count(1, "select count(*) from pg_catalog.pg_class where relname = 'test_poly'");
 
   // expect 2 polygons if not in multi(geometry) mode, or 1 if multi(geometry)
   // mode is enabled.
   if (enable_multi) {
-    check_count(test_conn, 1, "select count(*) from test_poly");
-    check_count(test_conn, 1, "select count(*) from test_poly where foo='bar'");
-    check_count(test_conn, 1, "select count(*) from test_poly where bar='baz'");
+    db->check_count(1, "select count(*) from test_poly");
+    db->check_count(1, "select count(*) from test_poly where foo='bar'");
+    db->check_count(1, "select count(*) from test_poly where bar='baz'");
 
     // there should be two 5-pointed polygons in the multipolygon (note that
     // it's 5 points including the duplicated first/last point)
-    check_count(test_conn, 2, "select count(*) from (select (st_dump(way)).geom as way from test_poly) x");
-    check_count(test_conn, 5, "select distinct st_numpoints(st_exteriorring(way)) from (select (st_dump(way)).geom as way from test_poly) x");
+    db->check_count(2, "select count(*) from (select (st_dump(way)).geom as way from test_poly) x");
+    db->check_count(5, "select distinct st_numpoints(st_exteriorring(way)) from (select (st_dump(way)).geom as way from test_poly) x");
 
   } else {
-    check_count(test_conn, 2, "select count(*) from test_poly");
-    check_count(test_conn, 2, "select count(*) from test_poly where foo='bar'");
-    check_count(test_conn, 2, "select count(*) from test_poly where bar='baz'");
+    db->check_count(2, "select count(*) from test_poly");
+    db->check_count(2, "select count(*) from test_poly where foo='bar'");
+    db->check_count(2, "select count(*) from test_poly where bar='baz'");
 
     // although there are 2 rows, they should both be 5-pointed polygons (note
     // that it's 5 points including the duplicated first/last point)
-    check_count(test_conn, 5, "select distinct st_numpoints(st_exteriorring(way)) from test_poly");
+    db->check_count(5, "select distinct st_numpoints(st_exteriorring(way)) from test_poly");
   }
 }
 
 int main(int argc, char *argv[]) {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::shared_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -122,8 +88,8 @@ int main(int argc, char *argv[]) {
     }
 
     try {
-        check_output_poly_trivial(0, db->conninfo());
-        check_output_poly_trivial(1, db->conninfo());
+        check_output_poly_trivial(0, db);
+        check_output_poly_trivial(1, db);
         return 0;
 
     } catch (const std::exception &e) {
diff --git a/tests/test-output-multi-polygon.cpp b/tests/test-output-multi-polygon.cpp
index 98370c6..f0086f7 100644
--- a/tests/test-output-multi-polygon.cpp
+++ b/tests/test-output-multi-polygon.cpp
@@ -13,41 +13,18 @@
 #include "options.hpp"
 #include "middle-pgsql.hpp"
 #include "taginfo_impl.hpp"
-#include "parse.hpp"
 
-#include <libpq-fe.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <boost/scoped_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 
 #include "tests/middle-tests.hpp"
 #include "tests/common-pg.hpp"
-
-void check_count(pg::conn_ptr &conn, int expected, const std::string &query) {
-    pg::result_ptr res = conn->exec(query);
-
-    int ntuples = PQntuples(res->get());
-    if (ntuples != 1) {
-        throw std::runtime_error((boost::format("Expected only one tuple from a query "
-                                                "to check COUNT(*), but got %1%. Query "
-                                                "was: %2%.")
-                                  % ntuples % query).str());
-    }
-
-    std::string numstr = PQgetvalue(res->get(), 0, 0);
-    int count = boost::lexical_cast<int>(numstr);
-
-    if (count != expected) {
-        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
-                                                "query: %3%.")
-                                  % expected % count % query).str());
-    }
-}
+#include "tests/common.hpp"
 
 int main(int argc, char *argv[]) {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::unique_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -57,59 +34,47 @@ int main(int argc, char *argv[]) {
     }
 
     try {
-        boost::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
+        std::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
         options_t options;
-        options.conninfo = db->conninfo().c_str();
+        options.database_options = db->database_options;
         options.num_procs = 1;
         options.prefix = "osm2pgsql_test";
-        options.slim = 1;
+        options.slim = true;
 
-        boost::shared_ptr<geometry_processor> processor = geometry_processor::create("polygon", &options);
+        std::shared_ptr<geometry_processor> processor = geometry_processor::create("polygon", &options);
 
         export_list columns;
         { taginfo info; info.name = "building"; info.type = "text"; columns.add(OSMTYPE_WAY, info); }
 
-        boost::shared_ptr<output_multi_t> out_test(new output_multi_t("foobar_buildings", processor, columns, mid_pgsql.get(), options));
+        auto out_test = std::make_shared<output_multi_t>("foobar_buildings", processor, columns, mid_pgsql.get(), options);
 
         osmdata_t osmdata(mid_pgsql, out_test);
 
-        boost::scoped_ptr<parse_delegate_t> parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection));
-
-        osmdata.start();
-
-        if (parser->streamFile("pbf", "tests/liechtenstein-2013-08-03.osm.pbf", options.sanitize, &osmdata) != 0) {
-            throw std::runtime_error("Unable to read input file `tests/liechtenstein-2013-08-03.osm.pbf'.");
-        }
-
-        parser.reset(NULL);
-
-        osmdata.stop();
-
-        // start a new connection to run tests on
-        pg::conn_ptr test_conn = pg::conn::connect(db->conninfo());
+        testing::parse("tests/liechtenstein-2013-08-03.osm.pbf", "pbf",
+                       options, &osmdata);
 
-        check_count(test_conn, 1, "select count(*) from pg_catalog.pg_class where relname = 'foobar_buildings'");
-        check_count(test_conn, 0, "select count(*) from foobar_buildings where building is null");
-        check_count(test_conn, 3723, "select count(*) from foobar_buildings");
+        db->check_count(1, "select count(*) from pg_catalog.pg_class where relname = 'foobar_buildings'");
+        db->check_count(0, "select count(*) from foobar_buildings where building is null");
+        db->check_count(3723, "select count(*) from foobar_buildings");
 
         //check that we have the right spread
-        check_count(test_conn, 1, "select count(*) from foobar_buildings where building='barn'");
-        check_count(test_conn, 1, "select count(*) from foobar_buildings where building='chapel'");
-        check_count(test_conn, 5, "select count(*) from foobar_buildings where building='church'");
-        check_count(test_conn, 3, "select count(*) from foobar_buildings where building='commercial'");
-        check_count(test_conn, 6, "select count(*) from foobar_buildings where building='farm'");
-        check_count(test_conn, 1, "select count(*) from foobar_buildings where building='garage'");
-        check_count(test_conn, 2, "select count(*) from foobar_buildings where building='glasshouse'");
-        check_count(test_conn, 1, "select count(*) from foobar_buildings where building='greenhouse'");
-        check_count(test_conn, 153, "select count(*) from foobar_buildings where building='house'");
-        check_count(test_conn, 4, "select count(*) from foobar_buildings where building='hut'");
-        check_count(test_conn, 8, "select count(*) from foobar_buildings where building='industrial'");
-        check_count(test_conn, 200, "select count(*) from foobar_buildings where building='residential'");
-        check_count(test_conn, 6, "select count(*) from foobar_buildings where building='roof'");
-        check_count(test_conn, 4, "select count(*) from foobar_buildings where building='school'");
-        check_count(test_conn, 2, "select count(*) from foobar_buildings where building='station'");
-        check_count(test_conn, 3, "select count(*) from foobar_buildings where building='warehouse'");
-        check_count(test_conn, 3323, "select count(*) from foobar_buildings where building='yes'");
+        db->check_count(1, "select count(*) from foobar_buildings where building='barn'");
+        db->check_count(1, "select count(*) from foobar_buildings where building='chapel'");
+        db->check_count(5, "select count(*) from foobar_buildings where building='church'");
+        db->check_count(3, "select count(*) from foobar_buildings where building='commercial'");
+        db->check_count(6, "select count(*) from foobar_buildings where building='farm'");
+        db->check_count(1, "select count(*) from foobar_buildings where building='garage'");
+        db->check_count(2, "select count(*) from foobar_buildings where building='glasshouse'");
+        db->check_count(1, "select count(*) from foobar_buildings where building='greenhouse'");
+        db->check_count(153, "select count(*) from foobar_buildings where building='house'");
+        db->check_count(4, "select count(*) from foobar_buildings where building='hut'");
+        db->check_count(8, "select count(*) from foobar_buildings where building='industrial'");
+        db->check_count(200, "select count(*) from foobar_buildings where building='residential'");
+        db->check_count(6, "select count(*) from foobar_buildings where building='roof'");
+        db->check_count(4, "select count(*) from foobar_buildings where building='school'");
+        db->check_count(2, "select count(*) from foobar_buildings where building='station'");
+        db->check_count(3, "select count(*) from foobar_buildings where building='warehouse'");
+        db->check_count(3323, "select count(*) from foobar_buildings where building='yes'");
         return 0;
 
     } catch (const std::exception &e) {
diff --git a/tests/test-output-multi-tags.cpp b/tests/test-output-multi-tags.cpp
index 00b6d4e..b8d2b0f 100644
--- a/tests/test-output-multi-tags.cpp
+++ b/tests/test-output-multi-tags.cpp
@@ -13,41 +13,18 @@
 #include "options.hpp"
 #include "osmdata.hpp"
 #include "taginfo_impl.hpp"
-#include "parse.hpp"
 
-#include <libpq-fe.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <boost/scoped_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 
 #include "tests/middle-tests.hpp"
 #include "tests/common-pg.hpp"
-
-void check_count(pg::conn_ptr &conn, int expected, const std::string &query) {
-    pg::result_ptr res = conn->exec(query);
-
-    int ntuples = PQntuples(res->get());
-    if (ntuples != 1) {
-        throw std::runtime_error((boost::format("Expected only one tuple from a query "
-                                                "to check COUNT(*), but got %1%. Query "
-                                                "was: %2%.")
-                                  % ntuples % query).str());
-    }
-
-    std::string numstr = PQgetvalue(res->get(), 0, 0);
-    int count = boost::lexical_cast<int>(numstr);
-
-    if (count != expected) {
-        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
-                                                "query: %3%.")
-                                  % expected % count % query).str());
-    }
-}
+#include "tests/common.hpp"
 
 int main(int argc, char *argv[]) {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::unique_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -58,64 +35,53 @@ int main(int argc, char *argv[]) {
 
     try {
         options_t options;
-        options.conninfo = db->conninfo().c_str();
+        options.database_options = db->database_options;
         options.num_procs = 1;
-        options.slim = 1;
+        options.slim = true;
 
-        options.projection.reset(new reprojection(PROJ_LATLONG));
+        options.projection.reset(reprojection::create_projection(PROJ_LATLONG));
 
         options.output_backend = "multi";
         options.style = "tests/test_output_multi_tags.json";
 
-        //setup the front (input)
-        parse_delegate_t parser(options.extra_attributes, options.bbox, options.projection);
-
         //setup the middle
-        boost::shared_ptr<middle_t> middle = middle_t::create_middle(options.slim);
+        std::shared_ptr<middle_t> middle = middle_t::create_middle(options.slim);
 
         //setup the backend (output)
-        std::vector<boost::shared_ptr<output_t> > outputs = output_t::create_outputs(middle.get(), options);
+        std::vector<std::shared_ptr<output_t> > outputs = output_t::create_outputs(middle.get(), options);
 
         //let osmdata orchestrate between the middle and the outs
         osmdata_t osmdata(middle, outputs);
 
-        osmdata.start();
-
-        if (parser.streamFile("libxml2", "tests/test_output_multi_tags.osm", options.sanitize, &osmdata) != 0) {
-            throw std::runtime_error("Unable to read input file `tests/test_output_multi_line_storage.osm'.");
-        }
-
-        osmdata.stop();
-
-        // start a new connection to run tests on
-        pg::conn_ptr test_conn = pg::conn::connect(db->conninfo());
+        testing::parse("tests/test_output_multi_tags.osm", "xml",
+                       options, &osmdata);
 
         // Check we got the right tables
-        check_count(test_conn, 1, "select count(*) from pg_catalog.pg_class where relname = 'test_points_1'");
-        check_count(test_conn, 1, "select count(*) from pg_catalog.pg_class where relname = 'test_points_2'");
-        check_count(test_conn, 1, "select count(*) from pg_catalog.pg_class where relname = 'test_line_1'");
-        check_count(test_conn, 1, "select count(*) from pg_catalog.pg_class where relname = 'test_polygon_1'");
-        check_count(test_conn, 1, "select count(*) from pg_catalog.pg_class where relname = 'test_polygon_2'");
+        db->check_count(1, "select count(*) from pg_catalog.pg_class where relname = 'test_points_1'");
+        db->check_count(1, "select count(*) from pg_catalog.pg_class where relname = 'test_points_2'");
+        db->check_count(1, "select count(*) from pg_catalog.pg_class where relname = 'test_line_1'");
+        db->check_count(1, "select count(*) from pg_catalog.pg_class where relname = 'test_polygon_1'");
+        db->check_count(1, "select count(*) from pg_catalog.pg_class where relname = 'test_polygon_2'");
 
         // Check we didn't get any extra in the tables
-        check_count(test_conn, 2, "select count(*) from test_points_1");
-        check_count(test_conn, 2, "select count(*) from test_points_2");
-        check_count(test_conn, 1, "select count(*) from test_line_1");
-        check_count(test_conn, 1, "select count(*) from test_line_2");
-        check_count(test_conn, 1, "select count(*) from test_polygon_1");
-        check_count(test_conn, 1, "select count(*) from test_polygon_2");
+        db->check_count(2, "select count(*) from test_points_1");
+        db->check_count(2, "select count(*) from test_points_2");
+        db->check_count(1, "select count(*) from test_line_1");
+        db->check_count(1, "select count(*) from test_line_2");
+        db->check_count(1, "select count(*) from test_polygon_1");
+        db->check_count(1, "select count(*) from test_polygon_2");
 
         // Check that the first table for each type got the right transform
-        check_count(test_conn, 1, "SELECT COUNT(*) FROM test_points_1 WHERE foo IS NULL and bar = 'n1' AND baz IS NULL");
-        check_count(test_conn, 1, "SELECT COUNT(*) FROM test_points_1 WHERE foo IS NULL and bar = 'n2' AND baz IS NULL");
-        check_count(test_conn, 1, "SELECT COUNT(*) FROM test_line_1 WHERE foo IS NULL and bar = 'w1' AND baz IS NULL");
-        check_count(test_conn, 1, "SELECT COUNT(*) FROM test_polygon_1 WHERE foo IS NULL and bar = 'w2' AND baz IS NULL");
+        db->check_count(1, "SELECT COUNT(*) FROM test_points_1 WHERE foo IS NULL and bar = 'n1' AND baz IS NULL");
+        db->check_count(1, "SELECT COUNT(*) FROM test_points_1 WHERE foo IS NULL and bar = 'n2' AND baz IS NULL");
+        db->check_count(1, "SELECT COUNT(*) FROM test_line_1 WHERE foo IS NULL and bar = 'w1' AND baz IS NULL");
+        db->check_count(1, "SELECT COUNT(*) FROM test_polygon_1 WHERE foo IS NULL and bar = 'w2' AND baz IS NULL");
 
         // Check that the second table also got the right transform
-        check_count(test_conn, 1, "SELECT COUNT(*) FROM test_points_2 WHERE foo IS NULL and bar IS NULL AND baz = 'n1'");
-        check_count(test_conn, 1, "SELECT COUNT(*) FROM test_points_2 WHERE foo IS NULL and bar IS NULL AND baz = 'n2'");
-        check_count(test_conn, 1, "SELECT COUNT(*) FROM test_line_2 WHERE foo IS NULL and bar IS NULL AND baz = 'w1'");
-        check_count(test_conn, 1, "SELECT COUNT(*) FROM test_polygon_2 WHERE foo IS NULL and bar IS NULL AND baz = 'w2'");
+        db->check_count(1, "SELECT COUNT(*) FROM test_points_2 WHERE foo IS NULL and bar IS NULL AND baz = 'n1'");
+        db->check_count(1, "SELECT COUNT(*) FROM test_points_2 WHERE foo IS NULL and bar IS NULL AND baz = 'n2'");
+        db->check_count(1, "SELECT COUNT(*) FROM test_line_2 WHERE foo IS NULL and bar IS NULL AND baz = 'w1'");
+        db->check_count(1, "SELECT COUNT(*) FROM test_polygon_2 WHERE foo IS NULL and bar IS NULL AND baz = 'w2'");
 
         return 0;
 
diff --git a/tests/test-output-pgsql-area.cpp b/tests/test-output-pgsql-area.cpp
new file mode 100644
index 0000000..5fc23cc
--- /dev/null
+++ b/tests/test-output-pgsql-area.cpp
@@ -0,0 +1,107 @@
+/**
+
+Test the area reprojection functionality of osm2pgsql 
+
+The idea behind that functionality is to populate the way_area
+column with the area that a polygoun would have in EPSG:3857, 
+rather than the area it actually has in the coordinate system
+used for importing.
+
+*/
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <cassert>
+#include <sstream>
+#include <stdexcept>
+#include <memory>
+
+#include "osmtypes.hpp"
+#include "osmdata.hpp"
+#include "middle.hpp"
+#include "output-pgsql.hpp"
+#include "options.hpp"
+#include "middle-pgsql.hpp"
+#include "middle-ram.hpp"
+#include "taginfo_impl.hpp"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include "tests/common-pg.hpp"
+#include "tests/common.hpp"
+
+void run_test(const char* test_name, void (*testfunc)()) {
+    try {
+        fprintf(stderr, "%s\n", test_name);
+        testfunc();
+
+    } catch (const std::exception& e) {
+        fprintf(stderr, "%s\n", e.what());
+        fprintf(stderr, "FAIL\n");
+        exit(EXIT_FAILURE);
+    }
+
+    fprintf(stderr, "PASS\n");
+}
+#define RUN_TEST(x) run_test(#x, &(x))
+
+
+void test_area_base(bool latlon, bool reproj, double expect_area_poly, double expect_area_multi) {
+    std::unique_ptr<pg::tempdb> db;
+
+    try {
+        db.reset(new pg::tempdb);
+    } catch (const std::exception &e) {
+        std::cerr << "Unable to setup database: " << e.what() << "\n";
+        exit(77);
+    }
+
+    std::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
+    options_t options;
+    options.database_options = db->database_options;
+    options.num_procs = 1;
+    options.style = "default.style";
+    options.prefix = "osm2pgsql_test";
+    if (latlon) {
+        options.projection.reset(reprojection::create_projection(PROJ_LATLONG));
+    }
+    if (reproj) {
+        options.reproject_area = true;
+    }
+    options.scale = latlon ? 10000000 : 100;
+
+    auto out_test = std::make_shared<output_pgsql_t>(mid_pgsql.get(), options);
+
+    osmdata_t osmdata(mid_pgsql, out_test);
+    testing::parse("tests/test_output_pgsql_area.osm", "xml",
+                   options, &osmdata);
+
+    db->check_count(2, "SELECT COUNT(*) FROM osm2pgsql_test_polygon");
+    db->check_number(expect_area_poly, "SELECT way_area FROM osm2pgsql_test_polygon WHERE name='poly'");
+    db->check_number(expect_area_multi, "SELECT way_area FROM osm2pgsql_test_polygon WHERE name='multi'");
+
+    return;
+}
+
+void test_area_classic() {
+    test_area_base(false, false, 1.23927e+10, 9.91828e+10);
+}
+
+void test_area_latlon() {
+    test_area_base(true, false, 1, 8);
+}
+
+void test_area_latlon_with_reprojection() {
+    test_area_base(true, true, 1.23927e+10, 9.91828e+10);
+}
+
+int main(int argc, char *argv[]) {
+    RUN_TEST(test_area_latlon);
+    RUN_TEST(test_area_classic);
+    RUN_TEST(test_area_latlon_with_reprojection);
+    return 0;
+}
diff --git a/tests/test-output-pgsql-schema.cpp b/tests/test-output-pgsql-schema.cpp
new file mode 100644
index 0000000..f744949
--- /dev/null
+++ b/tests/test-output-pgsql-schema.cpp
@@ -0,0 +1,110 @@
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <cassert>
+#include <sstream>
+#include <stdexcept>
+#include <memory>
+
+#include "osmtypes.hpp"
+#include "osmdata.hpp"
+#include "output-pgsql.hpp"
+#include "options.hpp"
+#include "middle-pgsql.hpp"
+#include "middle-ram.hpp"
+#include "taginfo_impl.hpp"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include "tests/common-pg.hpp"
+#include "tests/common.hpp"
+
+namespace {
+
+struct skip_test : public std::exception {
+    const char *what() const noexcept { return "Test skipped."; }
+};
+
+void run_test(const char* test_name, void (*testfunc)()) {
+    try {
+        fprintf(stderr, "%s\n", test_name);
+        testfunc();
+
+    } catch (const skip_test &) {
+        exit(77); // <-- code to skip this test.
+
+    } catch (const std::exception& e) {
+        fprintf(stderr, "%s\n", e.what());
+        fprintf(stderr, "FAIL\n");
+        exit(EXIT_FAILURE);
+    }
+
+    fprintf(stderr, "PASS\n");
+}
+#define RUN_TEST(x) run_test(#x, &(x))
+
+void test_other_output_schema() {
+    std::unique_ptr<pg::tempdb> db;
+
+    try {
+        db.reset(new pg::tempdb);
+    } catch (const std::exception &e) {
+        std::cerr << "Unable to setup database: " << e.what() << "\n";
+        throw skip_test();
+    }
+
+    pg::conn_ptr schema_conn = pg::conn::connect(db->database_options);
+
+    schema_conn->exec("CREATE SCHEMA myschema;"
+                      "CREATE TABLE myschema.osm2pgsql_test_point (id bigint);"
+                      "CREATE TABLE myschema.osm2pgsql_test_line (id bigint);"
+                      "CREATE TABLE myschema.osm2pgsql_test_polygon (id bigint);"
+                      "CREATE TABLE myschema.osm2pgsql_test_roads (id bigint)");
+
+    std::string proc_name("test-output-pgsql-schema"), input_file("-");
+    char *argv[] = { &proc_name[0], &input_file[0], nullptr };
+
+    std::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
+    options_t options = options_t(2, argv);
+    options.database_options = db->database_options;
+    options.num_procs = 1;
+    options.prefix = "osm2pgsql_test";
+    options.style = "default.style";
+
+    auto out_test = std::make_shared<output_pgsql_t>(mid_pgsql.get(), options);
+
+    osmdata_t osmdata(mid_pgsql, out_test);
+
+    testing::parse("tests/test_output_pgsql_z_order.osm", "xml",
+                   options, &osmdata);
+
+    db->assert_has_table("public.osm2pgsql_test_point");
+    db->assert_has_table("public.osm2pgsql_test_line");
+    db->assert_has_table("public.osm2pgsql_test_polygon");
+    db->assert_has_table("public.osm2pgsql_test_roads");
+    db->assert_has_table("public.osm2pgsql_test_point");
+    db->assert_has_table("public.osm2pgsql_test_line");
+    db->assert_has_table("public.osm2pgsql_test_polygon");
+    db->assert_has_table("public.osm2pgsql_test_roads");
+
+    db->check_count( 2, "SELECT COUNT(*) FROM osm2pgsql_test_point");
+    db->check_count( 11, "SELECT COUNT(*) FROM osm2pgsql_test_line");
+    db->check_count( 1, "SELECT COUNT(*) FROM osm2pgsql_test_polygon");
+    db->check_count( 8, "SELECT COUNT(*) FROM osm2pgsql_test_roads");
+    db->check_count( 0, "SELECT COUNT(*) FROM myschema.osm2pgsql_test_point");
+    db->check_count( 0, "SELECT COUNT(*) FROM myschema.osm2pgsql_test_line");
+    db->check_count( 0, "SELECT COUNT(*) FROM myschema.osm2pgsql_test_polygon");
+    db->check_count( 0, "SELECT COUNT(*) FROM myschema.osm2pgsql_test_roads");
+}
+
+} // anonymous namespace
+
+int main(int argc, char *argv[]) {
+    RUN_TEST(test_other_output_schema);
+
+    return 0;
+}
diff --git a/tests/test-output-pgsql-tablespace.cpp b/tests/test-output-pgsql-tablespace.cpp
old mode 100755
new mode 100644
index 3f75299..6b96ca2
--- a/tests/test-output-pgsql-tablespace.cpp
+++ b/tests/test-output-pgsql-tablespace.cpp
@@ -14,22 +14,20 @@
 #include "middle-pgsql.hpp"
 #include "middle-ram.hpp"
 #include "taginfo_impl.hpp"
-#include "parse.hpp"
 
-#include <libpq-fe.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <boost/scoped_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 
 #include "tests/middle-tests.hpp"
 #include "tests/common-pg.hpp"
+#include "tests/common.hpp"
 
 namespace {
 
 struct skip_test : public std::exception {
-    const char *what() { return "Test skipped."; }
+    const char *what() const noexcept { return "Test skipped."; }
 };
 
 void run_test(const char* test_name, void (*testfunc)()) {
@@ -50,40 +48,11 @@ void run_test(const char* test_name, void (*testfunc)()) {
 }
 #define RUN_TEST(x) run_test(#x, &(x))
 
-void check_count(pg::conn_ptr &conn, int expected, const std::string &query) {
-    pg::result_ptr res = conn->exec(query);
-
-    int ntuples = PQntuples(res->get());
-    if (ntuples != 1) {
-        throw std::runtime_error((boost::format("Expected only one tuple from a query "
-                                                "to check COUNT(*), but got %1%. Query "
-                                                "was: %2%.")
-                                  % ntuples % query).str());
-    }
-
-    std::string numstr = PQgetvalue(res->get(), 0, 0);
-    int count = boost::lexical_cast<int>(numstr);
-
-    if (count != expected) {
-        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
-                                                "query: %3%.")
-                                  % expected % count % query).str());
-    }
-}
-
-void assert_has_table(pg::conn_ptr &test_conn, const std::string &table_name) {
-    std::string query = (boost::format("select count(*) from pg_catalog.pg_class "
-                                       "where relname = '%1%'")
-                         % table_name).str();
-
-    check_count(test_conn, 1, query);
-}
-
 // "simple" test modeled on the basic regression test from
 // the python script. this is just to check everything is
 // working as expected before we start the complex stuff.
 void test_regression_simple() {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::unique_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -94,47 +63,35 @@ void test_regression_simple() {
     }
 
     std::string proc_name("test-output-pgsql"), input_file("-");
-    char *argv[] = { &proc_name[0], &input_file[0], NULL };
+    char *argv[] = { &proc_name[0], &input_file[0], nullptr };
 
-    boost::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
-    options_t options = options_t::parse(2, argv);
-    options.conninfo = db->conninfo().c_str();
+    std::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
+    options_t options = options_t(2, argv);
+    options.database_options = db->database_options;
     options.num_procs = 1;
     options.prefix = "osm2pgsql_test";
-    options.slim = 1;
+    options.slim = true;
     options.style = "default.style";
 
     options.tblsslim_index = "tablespacetest";
     options.tblsslim_data = "tablespacetest";
 
-    boost::shared_ptr<output_pgsql_t> out_test(new output_pgsql_t(mid_pgsql.get(), options));
+    auto out_test = std::make_shared<output_pgsql_t>(mid_pgsql.get(), options);
 
     osmdata_t osmdata(mid_pgsql, out_test);
 
-    boost::scoped_ptr<parse_delegate_t> parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection));
-
-    osmdata.start();
-
-    if (parser->streamFile("pbf", "tests/liechtenstein-2013-08-03.osm.pbf", options.sanitize, &osmdata) != 0) {
-        throw std::runtime_error("Unable to read input file `tests/liechtenstein-2013-08-03.osm.pbf'.");
-    }
-
-    parser.reset(NULL);
-
-    osmdata.stop();
-
-    // start a new connection to run tests on
-    pg::conn_ptr test_conn = pg::conn::connect(db->conninfo());
+    testing::parse("tests/liechtenstein-2013-08-03.osm.pbf", "pbf",
+                   options, &osmdata);
 
-    assert_has_table(test_conn, "osm2pgsql_test_point");
-    assert_has_table(test_conn, "osm2pgsql_test_line");
-    assert_has_table(test_conn, "osm2pgsql_test_polygon");
-    assert_has_table(test_conn, "osm2pgsql_test_roads");
+    db->assert_has_table("osm2pgsql_test_point");
+    db->assert_has_table("osm2pgsql_test_line");
+    db->assert_has_table("osm2pgsql_test_polygon");
+    db->assert_has_table("osm2pgsql_test_roads");
 
-    check_count(test_conn, 1342, "SELECT count(*) FROM osm2pgsql_test_point");
-    check_count(test_conn, 3300, "SELECT count(*) FROM osm2pgsql_test_line");
-    check_count(test_conn,  375, "SELECT count(*) FROM osm2pgsql_test_roads");
-    check_count(test_conn, 4128, "SELECT count(*) FROM osm2pgsql_test_polygon");
+    db->check_count(1342, "SELECT count(*) FROM osm2pgsql_test_point");
+    db->check_count(3300, "SELECT count(*) FROM osm2pgsql_test_line");
+    db->check_count( 375, "SELECT count(*) FROM osm2pgsql_test_roads");
+    db->check_count(4128, "SELECT count(*) FROM osm2pgsql_test_polygon");
 }
 
 } // anonymous namespace
diff --git a/tests/test-output-pgsql-z_order.cpp b/tests/test-output-pgsql-z_order.cpp
index c940f44..1fc865f 100644
--- a/tests/test-output-pgsql-z_order.cpp
+++ b/tests/test-output-pgsql-z_order.cpp
@@ -14,22 +14,20 @@
 #include "middle-pgsql.hpp"
 #include "middle-ram.hpp"
 #include "taginfo_impl.hpp"
-#include "parse.hpp"
 
-#include <libpq-fe.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <boost/scoped_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 
 #include "tests/middle-tests.hpp"
 #include "tests/common-pg.hpp"
+#include "tests/common.hpp"
 
 namespace {
 
 struct skip_test : public std::exception {
-    const char *what() { return "Test skipped."; }
+    const char *what() const noexcept { return "Test skipped."; }
 };
 
 void run_test(const char* test_name, void (*testfunc)()) {
@@ -50,82 +48,11 @@ void run_test(const char* test_name, void (*testfunc)()) {
 }
 #define RUN_TEST(x) run_test(#x, &(x))
 
-void check_string(pg::conn_ptr &conn, std::string expected, const std::string &query) {
-    pg::result_ptr res = conn->exec(query);
-
-    int ntuples = PQntuples(res->get());
-    if (ntuples != 1) {
-        throw std::runtime_error((boost::format("Expected only one tuple from a query "
-                                                "to check a string, but got %1%. Query "
-                                                "was: %2%.")
-                                  % ntuples % query).str());
-    }
-
-    std::string actual = PQgetvalue(res->get(), 0, 0);
-
-    if (actual != expected) {
-        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
-                                                "query: %3%.")
-                                  % expected % actual % query).str());
-    }
-}
-
-
-void check_count(pg::conn_ptr &conn, int expected, const std::string &query) {
-    pg::result_ptr res = conn->exec(query);
-
-    int ntuples = PQntuples(res->get());
-    if (ntuples != 1) {
-        throw std::runtime_error((boost::format("Expected only one tuple from a query "
-                                                "to check COUNT(*), but got %1%. Query "
-                                                "was: %2%.")
-                                  % ntuples % query).str());
-    }
-
-    std::string numstr = PQgetvalue(res->get(), 0, 0);
-    int count = boost::lexical_cast<int>(numstr);
-
-    if (count != expected) {
-        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
-                                                "query: %3%.")
-                                  % expected % count % query).str());
-    }
-}
-
-void check_number(pg::conn_ptr &conn, double expected, const std::string &query) {
-    pg::result_ptr res = conn->exec(query);
-
-    int ntuples = PQntuples(res->get());
-    if (ntuples != 1) {
-        throw std::runtime_error((boost::format("Expected only one tuple from a query, "
-                                                " but got %1%. Query was: %2%.")
-                                  % ntuples % query).str());
-    }
-
-    std::string numstr = PQgetvalue(res->get(), 0, 0);
-    double num = boost::lexical_cast<double>(numstr);
-
-    // floating point isn't exact, so allow a 0.01% difference
-    if ((num > 1.0001*expected) || (num < 0.9999*expected)) {
-        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
-                                                "query: %3%.")
-                                  % expected % num % query).str());
-    }
-}
-
-void assert_has_table(pg::conn_ptr &test_conn, const std::string &table_name) {
-    std::string query = (boost::format("select count(*) from pg_catalog.pg_class "
-                                       "where relname = '%1%'")
-                         % table_name).str();
-
-    check_count(test_conn, 1, query);
-}
-
 // "simple" test modeled on the basic regression test from
 // the python script. this is just to check everything is
 // working as expected before we start the complex stuff.
 void test_z_order() {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::unique_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -134,47 +61,35 @@ void test_z_order() {
         throw skip_test();
     }
 
-    std::string proc_name("test-output-pgsql"), input_file("-");
-    char *argv[] = { &proc_name[0], &input_file[0], NULL };
+    std::string proc_name("test-output-pgsql-z_order"), input_file("-");
+    char *argv[] = { &proc_name[0], &input_file[0], nullptr };
 
-    boost::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
-    options_t options = options_t::parse(2, argv);
-    options.conninfo = db->conninfo().c_str();
+    std::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
+    options_t options = options_t(2, argv);
+    options.database_options = db->database_options;
     options.num_procs = 1;
     options.prefix = "osm2pgsql_test";
     options.style = "default.style";
 
-    boost::shared_ptr<output_pgsql_t> out_test(new output_pgsql_t(mid_pgsql.get(), options));
+    auto out_test = std::make_shared<output_pgsql_t>(mid_pgsql.get(), options);
 
     osmdata_t osmdata(mid_pgsql, out_test);
 
-    boost::scoped_ptr<parse_delegate_t> parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection));
-
-    osmdata.start();
-
-    if (parser->streamFile("libxml2", "tests/test_output_pgsql_z_order.osm", options.sanitize, &osmdata) != 0) {
-        throw std::runtime_error("Unable to read input file `tests/test_output_pgsql_z_order.osm'.");
-    }
-
-    parser.reset(NULL);
-
-    osmdata.stop();
-
-    // start a new connection to run tests on
-    pg::conn_ptr test_conn = pg::conn::connect(db->conninfo());
+    testing::parse("tests/test_output_pgsql_z_order.osm", "xml",
+                   options, &osmdata);
 
-    assert_has_table(test_conn, "osm2pgsql_test_point");
-    assert_has_table(test_conn, "osm2pgsql_test_line");
-    assert_has_table(test_conn, "osm2pgsql_test_polygon");
-    assert_has_table(test_conn, "osm2pgsql_test_roads");
+    db->assert_has_table("osm2pgsql_test_point");
+    db->assert_has_table("osm2pgsql_test_line");
+    db->assert_has_table("osm2pgsql_test_polygon");
+    db->assert_has_table("osm2pgsql_test_roads");
 
-    check_string(test_conn, "motorway", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 0");
-    check_string(test_conn, "trunk", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 1");
-    check_string(test_conn, "primary", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 2");
-    check_string(test_conn, "secondary", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 3");
-    check_string(test_conn, "tertiary", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 4");
+    db->check_string("motorway", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 0");
+    db->check_string("trunk", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 1");
+    db->check_string("primary", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 2");
+    db->check_string("secondary", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 3");
+    db->check_string("tertiary", "SELECT highway FROM osm2pgsql_test_line WHERE layer IS NULL ORDER BY z_order DESC LIMIT 1 OFFSET 4");
 
-    check_string(test_conn, "residential", "SELECT highway FROM osm2pgsql_test_line ORDER BY z_order DESC LIMIT 1 OFFSET 0");
+    db->check_string("residential", "SELECT highway FROM osm2pgsql_test_line ORDER BY z_order DESC LIMIT 1 OFFSET 0");
 }
 
 } // anonymous namespace
diff --git a/tests/test-output-pgsql.cpp b/tests/test-output-pgsql.cpp
index b7a4053..5f7ba75 100644
--- a/tests/test-output-pgsql.cpp
+++ b/tests/test-output-pgsql.cpp
@@ -14,22 +14,23 @@
 #include "middle-pgsql.hpp"
 #include "middle-ram.hpp"
 #include "taginfo_impl.hpp"
-#include "parse.hpp"
 
-#include <libpq-fe.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <boost/scoped_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 
 #include "tests/middle-tests.hpp"
 #include "tests/common-pg.hpp"
+#include "tests/common-cleanup.hpp"
+#include "tests/common.hpp"
+
+#define FLAT_NODES_FILE_NAME "tests/test_output_pgsql_area_way.flat.nodes.bin"
 
 namespace {
 
 struct skip_test : public std::exception {
-    const char *what() { return "Test skipped."; }
+    const char *what() const noexcept { return "Test skipped."; }
 };
 
 void run_test(const char* test_name, void (*testfunc)()) {
@@ -50,61 +51,11 @@ void run_test(const char* test_name, void (*testfunc)()) {
 }
 #define RUN_TEST(x) run_test(#x, &(x))
 
-void check_count(pg::conn_ptr &conn, int expected, const std::string &query) {
-    pg::result_ptr res = conn->exec(query);
-
-    int ntuples = PQntuples(res->get());
-    if (ntuples != 1) {
-        throw std::runtime_error((boost::format("Expected only one tuple from a query "
-                                                "to check COUNT(*), but got %1%. Query "
-                                                "was: %2%.")
-                                  % ntuples % query).str());
-    }
-
-    std::string numstr = PQgetvalue(res->get(), 0, 0);
-    int count = boost::lexical_cast<int>(numstr);
-
-    if (count != expected) {
-        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
-                                                "query: %3%.")
-                                  % expected % count % query).str());
-    }
-}
-
-void check_number(pg::conn_ptr &conn, double expected, const std::string &query) {
-    pg::result_ptr res = conn->exec(query);
-
-    int ntuples = PQntuples(res->get());
-    if (ntuples != 1) {
-        throw std::runtime_error((boost::format("Expected only one tuple from a query, "
-                                                " but got %1%. Query was: %2%.")
-                                  % ntuples % query).str());
-    }
-
-    std::string numstr = PQgetvalue(res->get(), 0, 0);
-    double num = boost::lexical_cast<double>(numstr);
-
-    // floating point isn't exact, so allow a 0.01% difference
-    if ((num > 1.0001*expected) || (num < 0.9999*expected)) {
-        throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
-                                                "query: %3%.")
-                                  % expected % num % query).str());
-    }
-}
-
-void assert_has_table(pg::conn_ptr &test_conn, const std::string &table_name) {
-    std::string query = (boost::format("select count(*) from pg_catalog.pg_class "
-                                       "where relname = '%1%'")
-                         % table_name).str();
-
-    check_count(test_conn, 1, query);
-}
-
 // "simple" test modeled on the basic regression test from
 // the python script. this is just to check everything is
 // working as expected before we start the complex stuff.
 void test_regression_simple() {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::unique_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -114,59 +65,47 @@ void test_regression_simple() {
     }
 
     std::string proc_name("test-output-pgsql"), input_file("-");
-    char *argv[] = { &proc_name[0], &input_file[0], NULL };
+    char *argv[] = { &proc_name[0], &input_file[0], nullptr };
 
-    boost::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
-    options_t options = options_t::parse(2, argv);
-    options.conninfo = db->conninfo().c_str();
+    std::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
+    options_t options = options_t(2, argv);
+    options.database_options = db->database_options;
     options.num_procs = 1;
     options.prefix = "osm2pgsql_test";
-    options.slim = 1;
+    options.slim = true;
     options.style = "default.style";
 
-    boost::shared_ptr<output_pgsql_t> out_test(new output_pgsql_t(mid_pgsql.get(), options));
+    auto out_test = std::make_shared<output_pgsql_t>(mid_pgsql.get(), options);
 
     osmdata_t osmdata(mid_pgsql, out_test);
 
-    boost::scoped_ptr<parse_delegate_t> parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection));
-
-    osmdata.start();
+    testing::parse("tests/liechtenstein-2013-08-03.osm.pbf", "pbf",
+                   options, &osmdata);
 
-    if (parser->streamFile("pbf", "tests/liechtenstein-2013-08-03.osm.pbf", options.sanitize, &osmdata) != 0) {
-        throw std::runtime_error("Unable to read input file `tests/liechtenstein-2013-08-03.osm.pbf'.");
-    }
-
-    parser.reset(NULL);
-
-    osmdata.stop();
+    db->assert_has_table("osm2pgsql_test_point");
+    db->assert_has_table("osm2pgsql_test_line");
+    db->assert_has_table("osm2pgsql_test_polygon");
+    db->assert_has_table("osm2pgsql_test_roads");
 
-    // start a new connection to run tests on
-    pg::conn_ptr test_conn = pg::conn::connect(db->conninfo());
-
-    assert_has_table(test_conn, "osm2pgsql_test_point");
-    assert_has_table(test_conn, "osm2pgsql_test_line");
-    assert_has_table(test_conn, "osm2pgsql_test_polygon");
-    assert_has_table(test_conn, "osm2pgsql_test_roads");
-
-    check_count(test_conn, 1342, "SELECT count(*) FROM osm2pgsql_test_point");
-    check_count(test_conn, 3300, "SELECT count(*) FROM osm2pgsql_test_line");
-    check_count(test_conn,  375, "SELECT count(*) FROM osm2pgsql_test_roads");
-    check_count(test_conn, 4128, "SELECT count(*) FROM osm2pgsql_test_polygon");
+    db->check_count(1342, "SELECT count(*) FROM osm2pgsql_test_point");
+    db->check_count(3300, "SELECT count(*) FROM osm2pgsql_test_line");
+    db->check_count( 375, "SELECT count(*) FROM osm2pgsql_test_roads");
+    db->check_count(4128, "SELECT count(*) FROM osm2pgsql_test_polygon");
 
     // Check size of lines
-    check_number(test_conn, 1696.04, "SELECT ST_Length(way) FROM osm2pgsql_test_line WHERE osm_id = 44822682");
-    check_number(test_conn, 1151.26, "SELECT ST_Length(ST_Transform(way,4326)::geography) FROM osm2pgsql_test_line WHERE osm_id = 44822682");
+    db->check_number(1696.04, "SELECT ST_Length(way) FROM osm2pgsql_test_line WHERE osm_id = 44822682");
+    db->check_number(1151.26, "SELECT ST_Length(ST_Transform(way,4326)::geography) FROM osm2pgsql_test_line WHERE osm_id = 44822682");
 
-    check_number(test_conn, 311.21, "SELECT way_area FROM osm2pgsql_test_polygon WHERE osm_id = 157261342");
-    check_number(test_conn, 311.21, "SELECT ST_Area(way) FROM osm2pgsql_test_polygon WHERE osm_id = 157261342");
-    check_number(test_conn, 143.81, "SELECT ST_Area(ST_Transform(way,4326)::geography) FROM osm2pgsql_test_polygon WHERE osm_id = 157261342");
+    db->check_number(311.21, "SELECT way_area FROM osm2pgsql_test_polygon WHERE osm_id = 157261342");
+    db->check_number(311.21, "SELECT ST_Area(way) FROM osm2pgsql_test_polygon WHERE osm_id = 157261342");
+    db->check_number(143.81, "SELECT ST_Area(ST_Transform(way,4326)::geography) FROM osm2pgsql_test_polygon WHERE osm_id = 157261342");
 
     // Check a point's location
-    check_count(test_conn, 1, "SELECT count(*) FROM osm2pgsql_test_point WHERE ST_DWithin(way, 'SRID=900913;POINT(1062645.12 5972593.4)'::geometry, 0.1)");
+    db->check_count(1, "SELECT count(*) FROM osm2pgsql_test_point WHERE ST_DWithin(way, 'SRID=900913;POINT(1062645.12 5972593.4)'::geometry, 0.1)");
 }
 
 void test_latlong() {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::unique_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -176,63 +115,51 @@ void test_latlong() {
     }
 
     std::string proc_name("test-output-pgsql"), input_file("-");
-    char *argv[] = { &proc_name[0], &input_file[0], NULL };
+    char *argv[] = { &proc_name[0], &input_file[0], nullptr };
 
-    boost::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
-    options_t options = options_t::parse(2, argv);
-    options.conninfo = db->conninfo().c_str();
+    std::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
+    options_t options = options_t(2, argv);
+    options.database_options = db->database_options;
     options.num_procs = 1;
     options.prefix = "osm2pgsql_test";
-    options.slim = 1;
+    options.slim = true;
     options.style = "default.style";
 
-    options.projection.reset(new reprojection(PROJ_LATLONG));
-    options.scale = (options.projection->get_proj_id() == PROJ_LATLONG) ? 10000000 : 100;
+    options.projection.reset(reprojection::create_projection(PROJ_LATLONG));
+    options.scale = (options.projection->target_latlon()) ? 10000000 : 100;
 
-    boost::shared_ptr<output_pgsql_t> out_test(new output_pgsql_t(mid_pgsql.get(), options));
+    auto out_test = std::make_shared<output_pgsql_t>(mid_pgsql.get(), options);
 
     osmdata_t osmdata(mid_pgsql, out_test);
 
-    boost::scoped_ptr<parse_delegate_t> parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection));
+    testing::parse("tests/liechtenstein-2013-08-03.osm.pbf", "pbf",
+                   options, &osmdata);
 
-    osmdata.start();
+    db->assert_has_table("osm2pgsql_test_point");
+    db->assert_has_table("osm2pgsql_test_line");
+    db->assert_has_table("osm2pgsql_test_polygon");
+    db->assert_has_table("osm2pgsql_test_roads");
 
-    if (parser->streamFile("pbf", "tests/liechtenstein-2013-08-03.osm.pbf", options.sanitize, &osmdata) != 0) {
-        throw std::runtime_error("Unable to read input file `tests/liechtenstein-2013-08-03.osm.pbf'.");
-    }
-
-    parser.reset(NULL);
-
-    osmdata.stop();
-
-    // start a new connection to run tests on
-    pg::conn_ptr test_conn = pg::conn::connect(db->conninfo());
-
-    assert_has_table(test_conn, "osm2pgsql_test_point");
-    assert_has_table(test_conn, "osm2pgsql_test_line");
-    assert_has_table(test_conn, "osm2pgsql_test_polygon");
-    assert_has_table(test_conn, "osm2pgsql_test_roads");
-
-    check_count(test_conn, 1342, "SELECT count(*) FROM osm2pgsql_test_point");
-    check_count(test_conn, 3298, "SELECT count(*) FROM osm2pgsql_test_line");
-    check_count(test_conn, 374, "SELECT count(*) FROM osm2pgsql_test_roads");
-    check_count(test_conn, 4128, "SELECT count(*) FROM osm2pgsql_test_polygon");
+    db->check_count(1342, "SELECT count(*) FROM osm2pgsql_test_point");
+    db->check_count(3298, "SELECT count(*) FROM osm2pgsql_test_line");
+    db->check_count(374, "SELECT count(*) FROM osm2pgsql_test_roads");
+    db->check_count(4128, "SELECT count(*) FROM osm2pgsql_test_polygon");
 
     // Check size of lines
-    check_number(test_conn, 0.0105343, "SELECT ST_Length(way) FROM osm2pgsql_test_line WHERE osm_id = 44822682");
-    check_number(test_conn, 1151.26, "SELECT ST_Length(ST_Transform(way,4326)::geography) FROM osm2pgsql_test_line WHERE osm_id = 44822682");
+    db->check_number(0.0105343, "SELECT ST_Length(way) FROM osm2pgsql_test_line WHERE osm_id = 44822682");
+    db->check_number(1151.26, "SELECT ST_Length(ST_Transform(way,4326)::geography) FROM osm2pgsql_test_line WHERE osm_id = 44822682");
 
-    check_number(test_conn, 1.70718e-08, "SELECT way_area FROM osm2pgsql_test_polygon WHERE osm_id = 157261342");
-    check_number(test_conn, 1.70718e-08, "SELECT ST_Area(way) FROM osm2pgsql_test_polygon WHERE osm_id = 157261342");
-    check_number(test_conn, 143.845, "SELECT ST_Area(ST_Transform(way,4326)::geography) FROM osm2pgsql_test_polygon WHERE osm_id = 157261342");
+    db->check_number(1.70718e-08, "SELECT way_area FROM osm2pgsql_test_polygon WHERE osm_id = 157261342");
+    db->check_number(1.70718e-08, "SELECT ST_Area(way) FROM osm2pgsql_test_polygon WHERE osm_id = 157261342");
+    db->check_number(143.845, "SELECT ST_Area(ST_Transform(way,4326)::geography) FROM osm2pgsql_test_polygon WHERE osm_id = 157261342");
 
     // Check a point's location
-    check_count(test_conn, 1, "SELECT count(*) FROM osm2pgsql_test_point WHERE ST_DWithin(way, 'SRID=4326;POINT(9.5459035 47.1866494)'::geometry, 0.00001)");
+    db->check_count(1, "SELECT count(*) FROM osm2pgsql_test_point WHERE ST_DWithin(way, 'SRID=4326;POINT(9.5459035 47.1866494)'::geometry, 0.00001)");
 }
 
 
 void test_area_way_simple() {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::unique_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -242,50 +169,38 @@ void test_area_way_simple() {
     }
 
     std::string proc_name("test-output-pgsql"), input_file("-");
-    char *argv[] = { &proc_name[0], &input_file[0], NULL };
+    char *argv[] = { &proc_name[0], &input_file[0], nullptr };
 
-    boost::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
-    options_t options = options_t::parse(2, argv);
-    options.conninfo = db->conninfo().c_str();
+    std::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
+    options_t options = options_t(2, argv);
+    options.database_options = db->database_options;
     options.num_procs = 1;
     options.prefix = "osm2pgsql_test";
-    options.slim = 1;
+    options.slim = true;
     options.style = "default.style";
     options.flat_node_cache_enabled = true;
-    options.flat_node_file = boost::optional<std::string>("tests/test_output_pgsql_area_way.flat.nodes.bin");
+    options.flat_node_file = boost::optional<std::string>(FLAT_NODES_FILE_NAME);
 
-    boost::shared_ptr<output_pgsql_t> out_test(new output_pgsql_t(mid_pgsql.get(), options));
+    auto out_test = std::make_shared<output_pgsql_t>(mid_pgsql.get(), options);
 
     osmdata_t osmdata(mid_pgsql, out_test);
 
-    boost::scoped_ptr<parse_delegate_t> parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection));
-
-    osmdata.start();
+    testing::parse("tests/test_output_pgsql_way_area.osm", "xml",
+                   options, &osmdata);
 
-    if (parser->streamFile("libxml2", "tests/test_output_pgsql_way_area.osm", options.sanitize, &osmdata) != 0) {
-        throw std::runtime_error("Unable to read input file `tests/test_output_pgsql_way_area.osm'.");
-    }
-
-    parser.reset(NULL);
-
-    osmdata.stop();
+    db->assert_has_table("osm2pgsql_test_point");
+    db->assert_has_table("osm2pgsql_test_line");
+    db->assert_has_table("osm2pgsql_test_polygon");
+    db->assert_has_table("osm2pgsql_test_roads");
 
-    // start a new connection to run tests on
-    pg::conn_ptr test_conn = pg::conn::connect(db->conninfo());
-
-    assert_has_table(test_conn, "osm2pgsql_test_point");
-    assert_has_table(test_conn, "osm2pgsql_test_line");
-    assert_has_table(test_conn, "osm2pgsql_test_polygon");
-    assert_has_table(test_conn, "osm2pgsql_test_roads");
-
-    check_count(test_conn, 0, "SELECT count(*) FROM osm2pgsql_test_point");
-    check_count(test_conn, 0, "SELECT count(*) FROM osm2pgsql_test_line");
-    check_count(test_conn, 0, "SELECT count(*) FROM osm2pgsql_test_roads");
-    check_count(test_conn, 1, "SELECT count(*) FROM osm2pgsql_test_polygon");
+    db->check_count(0, "SELECT count(*) FROM osm2pgsql_test_point");
+    db->check_count(0, "SELECT count(*) FROM osm2pgsql_test_line");
+    db->check_count(0, "SELECT count(*) FROM osm2pgsql_test_roads");
+    db->check_count(1, "SELECT count(*) FROM osm2pgsql_test_polygon");
 }
 
 void test_route_rel() {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::unique_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -295,50 +210,38 @@ void test_route_rel() {
     }
 
     std::string proc_name("test-output-pgsql"), input_file("-");
-    char *argv[] = { &proc_name[0], &input_file[0], NULL };
+    char *argv[] = { &proc_name[0], &input_file[0], nullptr };
 
-    boost::shared_ptr<middle_ram_t> mid_ram(new middle_ram_t());
-    options_t options = options_t::parse(2, argv);
-    options.conninfo = db->conninfo().c_str();
+    std::shared_ptr<middle_ram_t> mid_ram(new middle_ram_t());
+    options_t options = options_t(2, argv);
+    options.database_options = db->database_options;
     options.num_procs = 1;
     options.prefix = "osm2pgsql_test";
-    options.slim = 0;
+    options.slim = false;
     options.style = "default.style";
 
-    boost::shared_ptr<output_pgsql_t> out_test(new output_pgsql_t(mid_ram.get(), options));
+    auto out_test = std::make_shared<output_pgsql_t>(mid_ram.get(), options);
 
     osmdata_t osmdata(mid_ram, out_test);
 
-    boost::scoped_ptr<parse_delegate_t> parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection));
-
-    osmdata.start();
+    testing::parse("tests/test_output_pgsql_route_rel.osm", "xml",
+                   options, &osmdata);
 
-    if (parser->streamFile("libxml2", "tests/test_output_pgsql_route_rel.osm", options.sanitize, &osmdata) != 0) {
-        throw std::runtime_error("Unable to read input file `tests/test_output_pgsql_way_area.osm'.");
-    }
-
-    parser.reset(NULL);
-
-    osmdata.stop();
+    db->assert_has_table("osm2pgsql_test_point");
+    db->assert_has_table("osm2pgsql_test_line");
+    db->assert_has_table("osm2pgsql_test_polygon");
+    db->assert_has_table("osm2pgsql_test_roads");
 
-    // start a new connection to run tests on
-    pg::conn_ptr test_conn = pg::conn::connect(db->conninfo());
-
-    assert_has_table(test_conn, "osm2pgsql_test_point");
-    assert_has_table(test_conn, "osm2pgsql_test_line");
-    assert_has_table(test_conn, "osm2pgsql_test_polygon");
-    assert_has_table(test_conn, "osm2pgsql_test_roads");
-
-    check_count(test_conn, 0, "SELECT count(*) FROM osm2pgsql_test_point");
-    check_count(test_conn, 2, "SELECT count(*) FROM osm2pgsql_test_line");
-    check_count(test_conn, 1, "SELECT count(*) FROM osm2pgsql_test_roads");
-    check_count(test_conn, 0, "SELECT count(*) FROM osm2pgsql_test_polygon");
+    db->check_count(0, "SELECT count(*) FROM osm2pgsql_test_point");
+    db->check_count(2, "SELECT count(*) FROM osm2pgsql_test_line");
+    db->check_count(1, "SELECT count(*) FROM osm2pgsql_test_roads");
+    db->check_count(0, "SELECT count(*) FROM osm2pgsql_test_polygon");
 }
 
 // test the same, but clone the output. it should
 // behave the same as the original.
 void test_clone() {
-    boost::scoped_ptr<pg::tempdb> db;
+    std::unique_ptr<pg::tempdb> db;
 
     try {
         db.reset(new pg::tempdb);
@@ -348,53 +251,45 @@ void test_clone() {
     }
 
     std::string proc_name("test-output-pgsql"), input_file("-");
-    char *argv[] = { &proc_name[0], &input_file[0], NULL };
+    char *argv[] = { &proc_name[0], &input_file[0], nullptr };
 
-    boost::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
-    options_t options = options_t::parse(2, argv);
-    options.conninfo = db->conninfo().c_str();
+    std::shared_ptr<middle_pgsql_t> mid_pgsql(new middle_pgsql_t());
+    options_t options = options_t(2, argv);
+    options.database_options = db->database_options;
     options.num_procs = 1;
     options.prefix = "osm2pgsql_test";
-    options.slim = 1;
+    options.slim = true;
     options.style = "default.style";
 
     output_pgsql_t out_test(mid_pgsql.get(), options);
 
     //TODO: make the middle testable too
-    //boost::shared_ptr<middle_t> mid_clone = mid_pgsql->get_instance();
-    boost::shared_ptr<output_t> out_clone = out_test.clone(mid_pgsql.get());
+    //std::shared_ptr<middle_t> mid_clone = mid_pgsql->get_instance();
+    std::shared_ptr<output_t> out_clone = out_test.clone(mid_pgsql.get());
 
     osmdata_t osmdata(mid_pgsql, out_clone);
 
-    boost::scoped_ptr<parse_delegate_t> parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection));
-
-    osmdata.start();
+    testing::parse("tests/liechtenstein-2013-08-03.osm.pbf", "pbf",
+                   options, &osmdata);
 
-    if (parser->streamFile("pbf", "tests/liechtenstein-2013-08-03.osm.pbf", options.sanitize, &osmdata) != 0) {
-        throw std::runtime_error("Unable to read input file `tests/liechtenstein-2013-08-03.osm.pbf'.");
-    }
-
-    parser.reset(NULL);
-
-    osmdata.stop();
+    db->assert_has_table("osm2pgsql_test_point");
+    db->assert_has_table("osm2pgsql_test_line");
+    db->assert_has_table("osm2pgsql_test_polygon");
+    db->assert_has_table("osm2pgsql_test_roads");
 
-    // start a new connection to run tests on
-    pg::conn_ptr test_conn = pg::conn::connect(db->conninfo());
-
-    assert_has_table(test_conn, "osm2pgsql_test_point");
-    assert_has_table(test_conn, "osm2pgsql_test_line");
-    assert_has_table(test_conn, "osm2pgsql_test_polygon");
-    assert_has_table(test_conn, "osm2pgsql_test_roads");
-
-    check_count(test_conn, 1342, "SELECT count(*) FROM osm2pgsql_test_point");
-    check_count(test_conn, 3300, "SELECT count(*) FROM osm2pgsql_test_line");
-    check_count(test_conn,  375, "SELECT count(*) FROM osm2pgsql_test_roads");
-    check_count(test_conn, 4128, "SELECT count(*) FROM osm2pgsql_test_polygon");
+    db->check_count(1342, "SELECT count(*) FROM osm2pgsql_test_point");
+    db->check_count(3300, "SELECT count(*) FROM osm2pgsql_test_line");
+    db->check_count( 375, "SELECT count(*) FROM osm2pgsql_test_roads");
+    db->check_count(4128, "SELECT count(*) FROM osm2pgsql_test_polygon");
 }
 
 } // anonymous namespace
 
 int main(int argc, char *argv[]) {
+    // remove flat nodes file  on exit - it's 20GB and bad manners to
+    // leave that lying around on the filesystem.
+    cleanup::file flat_nodes_file(FLAT_NODES_FILE_NAME);
+
     RUN_TEST(test_regression_simple);
     RUN_TEST(test_latlong);
     RUN_TEST(test_clone);
diff --git a/tests/test-parse-diff.cpp b/tests/test-parse-diff.cpp
new file mode 100644
index 0000000..144fd99
--- /dev/null
+++ b/tests/test-parse-diff.cpp
@@ -0,0 +1,126 @@
+#include <iostream>
+#include <memory>
+
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "middle.hpp"
+#include "tests/mockups.hpp"
+#include "options.hpp"
+#include "osmdata.hpp"
+#include "osmtypes.hpp"
+#include "output.hpp"
+#include "parse-osmium.hpp"
+
+void exit_nicely()
+{
+    fprintf(stderr, "Error occurred, cleaning up\n");
+    exit(1);
+}
+
+struct type_stats {
+    unsigned added = 0;
+    unsigned modified = 0;
+    unsigned deleted = 0;
+};
+
+struct test_output_t : public dummy_output_t {
+    type_stats node, way, rel;
+
+    explicit test_output_t(const options_t &options_)
+        : dummy_output_t(options_) {
+    }
+
+    virtual ~test_output_t() = default;
+
+    std::shared_ptr<output_t> clone(const middle_query_t *cloned_middle) const{
+        test_output_t *clone = new test_output_t(m_options);
+        clone->m_mid = cloned_middle;
+        return std::shared_ptr<output_t>(clone);
+    }
+
+    int node_add(osmid_t id, double, double, const taglist_t &) {
+        assert(id > 0);
+        ++node.added;
+        return 0;
+    }
+
+    int way_add(osmid_t id, const idlist_t &, const taglist_t &) {
+        assert(id > 0);
+        ++way.added;
+        return 0;
+    }
+
+    int relation_add(osmid_t id, const memberlist_t &, const taglist_t &) {
+        assert(id > 0);
+        ++rel.added;
+        return 0;
+    }
+
+    int node_modify(osmid_t, double, double, const taglist_t &) {
+        ++node.modified;
+        return 0;
+    }
+    int way_modify(osmid_t, const idlist_t &, const taglist_t &) {
+        ++way.modified;
+        return 0;
+    }
+    int relation_modify(osmid_t, const memberlist_t &, const taglist_t &) {
+        ++rel.modified;
+        return 0;
+    }
+
+    int node_delete(osmid_t) {
+        ++node.deleted;
+        return 0;
+    }
+    int way_delete(osmid_t) {
+        ++way.deleted;
+        return 0;
+    }
+    int relation_delete(osmid_t) {
+        ++rel.deleted;
+        return 0;
+    }
+
+};
+
+
+void assert_equal(uint64_t actual, uint64_t expected) {
+  if (actual != expected) {
+    std::cerr << "Expected " << expected << ", but got " << actual << ".\n";
+    exit(1);
+  }
+}
+
+int main() {
+
+  std::string inputfile = "tests/008-ch.osc.gz";
+
+  options_t options;
+
+  std::shared_ptr<reprojection> projection(reprojection::create_projection(PROJ_SPHERE_MERC));
+  options.projection = projection;
+
+  auto out_test = std::make_shared<test_output_t>(options);
+  osmdata_t osmdata(std::make_shared<dummy_slim_middle_t>(), out_test);
+
+  boost::optional<std::string> bbox;
+  parse_osmium_t parser(false, bbox, projection.get(), true, &osmdata);
+
+  parser.stream_file(inputfile, "");
+
+  assert_equal(out_test->node.added, 0);
+  assert_equal(out_test->node.modified, 1176);
+  assert_equal(out_test->node.deleted, 16773);
+  assert_equal(out_test->way.added, 0);
+  assert_equal(out_test->way.modified, 161);
+  assert_equal(out_test->way.deleted, 4);
+  assert_equal(out_test->rel.added, 0);
+  assert_equal(out_test->rel.modified, 11);
+  assert_equal(out_test->rel.deleted, 1);
+
+  return 0;
+}
diff --git a/tests/test-parse-xml2.cpp b/tests/test-parse-xml2.cpp
index e18f2d8..88eeef5 100644
--- a/tests/test-parse-xml2.cpp
+++ b/tests/test-parse-xml2.cpp
@@ -1,16 +1,18 @@
 #include <iostream>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <cassert>
+#include <memory>
 
-#include <boost/make_shared.hpp>
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
 
-#include "osmtypes.hpp"
+#include "middle.hpp"
+#include "tests/mockups.hpp"
+#include "options.hpp"
 #include "osmdata.hpp"
-#include "parse-xml2.hpp"
+#include "osmtypes.hpp"
 #include "output.hpp"
-#include "options.hpp"
+#include "parse-osmium.hpp"
 
 void exit_nicely()
 {
@@ -18,43 +20,11 @@ void exit_nicely()
     exit(1);
 }
 
-struct test_middle_t : public middle_t {
-    virtual ~test_middle_t() {}
-
-    int start(const options_t *out_options_) { return 0; }
-    void stop(void) { }
-    void cleanup(void) { }
-    void analyze(void) { }
-    void end(void) { }
-    void commit(void) { }
-
-    int nodes_set(osmid_t id, double lat, double lon, const taglist_t &tags) { return 0; }
-    int nodes_get_list(nodelist_t &out, const idlist_t nds) const { return 0; }
-
-    int ways_set(osmid_t id, const idlist_t &nds, const taglist_t &tags) { return 0; }
-    int ways_get(osmid_t id, taglist_t &tags, nodelist_t &nodes) const { return 0; }
-    int ways_get_list(const idlist_t &ids, idlist_t &way_ids,
-                              std::vector<taglist_t> &tags,
-                              std::vector<nodelist_t> &nodes) const { return 0; }
-
-    int relations_set(osmid_t id, const memberlist_t &members, const taglist_t &tags) { return 0; }
-    int relations_get(osmid_t id, memberlist_t &members, taglist_t &tags) const { return 0; }
-
-    void iterate_ways(pending_processor& pf) { }
-    void iterate_relations(pending_processor& pf) { }
-
-    virtual size_t pending_count() const { return 0; }
-
-    std::vector<osmid_t> relations_using_way(osmid_t way_id) const { return std::vector<osmid_t>(); }
-
-    virtual boost::shared_ptr<const middle_query_t> get_instance() const {return boost::shared_ptr<const middle_query_t>();}
-};
-
 struct test_output_t : public output_t {
     uint64_t sum_ids, num_nodes, num_ways, num_relations, num_nds, num_members;
 
     explicit test_output_t(const options_t &options_)
-        : output_t(NULL, options_), sum_ids(0), num_nodes(0), num_ways(0), num_relations(0),
+        : output_t(nullptr, options_), sum_ids(0), num_nodes(0), num_ways(0), num_relations(0),
           num_nds(0), num_members(0) {
     }
 
@@ -66,10 +36,10 @@ struct test_output_t : public output_t {
     virtual ~test_output_t() {
     }
 
-    boost::shared_ptr<output_t> clone(const middle_query_t *cloned_middle) const{
+    std::shared_ptr<output_t> clone(const middle_query_t *cloned_middle) const{
         test_output_t *clone = new test_output_t(*this);
         clone->m_mid = cloned_middle;
-        return boost::shared_ptr<output_t>(clone);
+        return std::shared_ptr<output_t>(clone);
     }
 
     int node_add(osmid_t id, double lat, double lon, const taglist_t &tags) {
@@ -129,28 +99,20 @@ void assert_equal(uint64_t actual, uint64_t expected) {
 }
 
 int main(int argc, char *argv[]) {
-  char *srcdir = getenv("srcdir");
 
-  if (srcdir == NULL) {
-    std::cerr << "$srcdir not set!\n";
-    return 1;
-  }
-
-  std::string inputfile = std::string(srcdir) + std::string("/tests/test_multipolygon.osm");
+  std::string inputfile = "tests/test_multipolygon.osm";
 
   options_t options;
-  boost::shared_ptr<reprojection> projection(new reprojection(PROJ_SPHERE_MERC));
+  std::shared_ptr<reprojection> projection(reprojection::create_projection(PROJ_SPHERE_MERC));
   options.projection = projection;
 
-  boost::shared_ptr<test_output_t> out_test(new test_output_t(options));
-  osmdata_t osmdata(boost::make_shared<test_middle_t>(), out_test);
+  auto out_test = std::make_shared<test_output_t>(options);
+  osmdata_t osmdata(std::make_shared<dummy_middle_t>(), out_test);
 
-  parse_xml2_t parser(0, false, projection, 0, 0, 0, 0);
+  boost::optional<std::string> bbox;
+  parse_osmium_t parser(false, bbox, projection.get(), false, &osmdata);
 
-  int ret = parser.streamFile(inputfile.c_str(), 0, &osmdata);
-  if (ret != 0) {
-    return ret;
-  }
+  parser.stream_file(inputfile, "");
 
   assert_equal(out_test->sum_ids,       73514L);
   assert_equal(out_test->num_nodes,       353L);
diff --git a/tests/test_output_pgsql_area.osm b/tests/test_output_pgsql_area.osm
new file mode 100644
index 0000000..260f11e
--- /dev/null
+++ b/tests/test_output_pgsql_area.osm
@@ -0,0 +1,55 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!--
+Nodes:
+        7     8
+   3 4   11 12
+         9  10
+   1 2  5     6
+-->
+<osm version="0.6">
+  <node id="1" version="1" lat="0" lon="0"/>
+  <node id="2" version="1" lat="0" lon="1"/>
+  <node id="3" version="1" lat="1" lon="0"/>
+  <node id="4" version="1" lat="1" lon="1"/>
+
+  <node id="5" version="1" lat="0" lon="2"/>
+  <node id="6" version="1" lat="0" lon="5"/>
+  <node id="7" version="1" lat="3" lon="2"/>
+  <node id="8" version="1" lat="3" lon="5"/>
+
+  <node id="9" version="1" lat="1" lon="3"/>
+  <node id="10" version="1" lat="1" lon="4"/>
+  <node id="11" version="1" lat="2" lon="3"/>
+  <node id="12" version="1" lat="2" lon="4"/>
+
+  <way id="1" version="1">
+    <nd ref="1"/>
+    <nd ref="2"/>
+    <nd ref="4"/>
+    <nd ref="3"/>
+    <nd ref="1"/>
+    <tag k="natural" v="water"/>
+    <tag k="name" v="poly"/>
+  </way>
+  <way id="2" version="1">
+    <nd ref="5"/>
+    <nd ref="6"/>
+    <nd ref="8"/>
+    <nd ref="7"/>
+    <nd ref="5"/>
+  </way>
+  <way id="3" version="1">
+    <nd ref="9"/>
+    <nd ref="10"/>
+    <nd ref="12"/>
+    <nd ref="11"/>
+    <nd ref="9"/>
+  </way>
+  <relation id='1' version='1'>
+    <member type="way" ref="2" role=""/>
+    <member type="way" ref="3" role=""/>
+    <tag k="type" v="multipolygon"/>
+    <tag k="natural" v="water"/>
+    <tag k="name" v="multi"/>
+  </relation>
+</osm>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/osm2pgsql.git



More information about the Pkg-grass-devel mailing list