[libosmium] 01/07: Imported Upstream version 2.4.0

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Sat Aug 29 11:17:33 UTC 2015


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

sebastic pushed a commit to branch master
in repository libosmium.

commit 93fff149e7a19202e1307c9f5b1443968b081b72
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sat Aug 29 12:04:56 2015 +0200

    Imported Upstream version 2.4.0
---
 CHANGELOG.md                                     |  34 ++-
 CMakeLists.txt                                   |  28 +-
 appveyor.yml                                     |  31 +--
 cmake/FindOsmium.cmake                           |  69 ++---
 examples/CMakeLists.txt                          |  26 +-
 examples/osmium_toogr.cpp                        | 244 -----------------
 examples/osmium_toogr2.cpp                       | 331 -----------------------
 examples/osmium_toogr2_exp.cpp                   | 305 ---------------------
 include/gdalcpp.hpp                              | 302 +++++++++++++++++++++
 include/osmium/area/problem_reporter_ogr.hpp     | 130 ++-------
 include/osmium/builder/osm_object_builder.hpp    |  67 ++---
 include/osmium/geom/factory.hpp                  |   1 +
 include/osmium/geom/ogr.hpp                      |  30 +-
 include/osmium/geom/tile.hpp                     |   4 +-
 include/osmium/io/detail/debug_output_format.hpp |   4 +-
 include/osmium/io/detail/input_format.hpp        |  11 +-
 include/osmium/io/detail/output_format.hpp       |   4 +-
 include/osmium/io/detail/pbf_decoder.hpp         |  29 +-
 include/osmium/io/detail/pbf_output_format.hpp   |  32 ++-
 include/osmium/io/detail/read_write.hpp          |   3 +
 include/osmium/io/detail/string_table.hpp        |  28 +-
 include/osmium/io/file.hpp                       |   3 +-
 include/osmium/io/reader.hpp                     |   6 +-
 include/osmium/io/writer.hpp                     |   2 +-
 include/osmium/osm/crc.hpp                       |  36 +--
 include/osmium/osm/types.hpp                     |   3 +
 include/osmium/util/delta.hpp                    |   8 +-
 include/osmium/util/memory_mapping.hpp           |   7 +
 include/protozero/varint.hpp                     |   4 -
 include/protozero/version.hpp                    |  22 ++
 scripts/travis_script.sh                         |   7 +
 test/data-tests/testdata-multipolygon.cpp        | 171 +++---------
 test/data-tests/testdata-overview.cpp            | 154 ++---------
 test/t/basic/test_crc.cpp                        |  21 ++
 test/t/basic/test_relation.cpp                   |  11 +
 test/t/tags/test_tag_list.cpp                    |  11 +
 36 files changed, 691 insertions(+), 1488 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 22eb06a..9b7bd8d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,35 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 
 ### Fixed
 
+
+## [2.4.0] - 2015-08-29
+
+### Added
+
+- Checks that user names, member roles and tag keys and values are not longer
+  than 256 * 4 bytes. That is the maximum length 256 Unicode characters
+  can have in UTF-8 encoding.
+- Support for GDAL 2. GDAL 1 still works.
+
+### Changed
+
+- Improved CMake build scripts.
+- Updated internal version of Protozero to 1.1.0.
+- Removed `toogr*` examples. They are in their own repository now.
+  See https://github.com/osmcode/osm-gis-export.
+- Files about to be memory-mapped (for instance index files) are now set
+  to binary mode on Windows so the application doesn't have to do this.
+
+### Fixed
+
+- Hanging program when trying to open file with an unknown file format.
+- Building problems with old boost versions.
+- Initialization errors in PBF writer.
+- Bug in byte swap code.
+- Output on Windows now always uses binary mode, even when writing to
+  stdout, so OSM xml and opl files always use LF line endings.
+
+
 ## [2.3.0] - 2015-08-18
 
 ### Added
@@ -108,8 +137,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
   Doxygen (up to version 1.8.8). This version contains a workaround to fix
   this.
 
-[unreleased]: https://github.com/osmcode/libosmium/compare/v2.3.0...HEAD
-[2.3.0]: https://github.com/osmcode/libosmium/compare/v2.3.0...v2.3.0
+[unreleased]: https://github.com/osmcode/libosmium/compare/v2.4.0...HEAD
+[2.4.0]: https://github.com/osmcode/libosmium/compare/v2.3.0...v2.4.0
+[2.3.0]: https://github.com/osmcode/libosmium/compare/v2.2.0...v2.3.0
 [2.2.0]: https://github.com/osmcode/libosmium/compare/v2.1.0...v2.2.0
 [2.1.0]: https://github.com/osmcode/libosmium/compare/v2.0.0...v2.1.0
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fba967a..fc08036 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,13 +26,11 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev;Cover
 project(libosmium)
 
 set(LIBOSMIUM_VERSION_MAJOR 2)
-set(LIBOSMIUM_VERSION_MINOR 3)
+set(LIBOSMIUM_VERSION_MINOR 4)
 set(LIBOSMIUM_VERSION_PATCH 0)
 
 set(LIBOSMIUM_VERSION
-    "${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}"
-    CACHE STRING
-    "Libosmium version")
+    "${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}")
 
 
 #-----------------------------------------------------------------------------
@@ -118,29 +116,39 @@ find_package(Boost 1.38)
 mark_as_advanced(CLEAR BOOST_ROOT)
 
 if(Boost_FOUND)
-    include_directories(${Boost_INCLUDE_DIRS})
+    include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
 else()
     set(BOOST_ROOT "NOT FOUND: please choose" CACHE PATH "")
     message(FATAL_ERROR "PLEASE, specify the directory where the Boost library is installed in BOOST_ROOT")
 endif()
 
-set(OSMIUM_INCLUDE_DIR include)
+# set OSMIUM_INCLUDE_DIR so FindOsmium will not set anything different
+set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")
+
+include_directories(${OSMIUM_INCLUDE_DIR})
+
 find_package(Osmium COMPONENTS io gdal geos proj sparsehash)
-include_directories(${OSMIUM_INCLUDE_DIRS})
+
+# The find_package put the directory where it found the libosmium includes
+# into OSMIUM_INCLUDE_DIRS. We remove it again, because we want to make
+# sure to use our own include directory already set up above.
+list(FIND OSMIUM_INCLUDE_DIRS "${OSMIUM_INCLUDE_DIR}" _own_index)
+list(REMOVE_AT OSMIUM_INCLUDE_DIRS ${_own_index})
+set(_own_index)
+
+include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS})
 
 if(MSVC)
     find_path(GETOPT_INCLUDE_DIR getopt.h)
     find_library(GETOPT_LIBRARY NAMES wingetopt)
     if(GETOPT_INCLUDE_DIR AND GETOPT_LIBRARY)
-        include_directories(${GETOPT_INCLUDE_DIR})
+        include_directories(SYSTEM ${GETOPT_INCLUDE_DIR})
         list(APPEND OSMIUM_LIBRARIES ${GETOPT_LIBRARY})
     else()
         set(GETOPT_MISSING 1)
     endif()
 endif()
 
-include_directories(include)
-
 
 #-----------------------------------------------------------------------------
 #
diff --git a/appveyor.yml b/appveyor.yml
index a05c396..8244d98 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -9,16 +9,10 @@ environment:
   - config: Dev
   - config: RelWithDebInfo
 
-# branches to build
-branches:
-  # whitelist
-  only:
-    - master
-
 shallow_clone: true
 
 # Operating system (build VM template)
-os: Visual Studio 2014 CTP4
+os: Visual Studio 2015
 
 # scripts that are called at very beginning, before repo cloning
 init:
@@ -46,6 +40,8 @@ install:
   - set PATH=%LODEPSDIR%\expat\lib;%PATH%
   #libtiff.dll
   - set PATH=%LODEPSDIR%\libtiff\lib;%PATH%
+  #jpeg.dll
+  - set PATH=%LODEPSDIR%\jpeg\lib;%PATH%
   #zlibwapi.dll
   - set PATH=%LODEPSDIR%\zlib\lib;%PATH%
   #convert backslashes in bzip2 path to forward slashes
@@ -71,27 +67,16 @@ build_script:
   # This will produce lots of LNK4099 warnings which can be ignored.
   # Unfortunately they can't be disabled, see
   # http://stackoverflow.com/questions/661606/visual-c-how-to-disable-specific-linker-warnings
-  - cmake .. -LA -G "Visual Studio 14 Win64"
+  - cmake -LA -G "Visual Studio 14 Win64"
     -DOsmium_DEBUG=TRUE
     -DCMAKE_BUILD_TYPE=%config%
     -DBUILD_HEADERS=OFF
     -DBOOST_ROOT=%LODEPSDIR%\boost
-    -DBoost_PROGRAM_OPTIONS_LIBRARY=%LODEPSDIR%\boost\lib\libboost_program_options-vc140-mt-1_57.lib
+    -DBoost_PROGRAM_OPTIONS_LIBRARY=%LODEPSDIR%\boost\lib\libboost_program_options-vc140-mt-1_58.lib
     -DZLIB_LIBRARY=%LODEPSDIR%\zlib\lib\zlibwapi.lib
-    -DZLIB_INCLUDE_DIR=%LODEPSDIR%\zlib\include
-    -DEXPAT_LIBRARY=%LODEPSDIR%\expat\lib\libexpat.lib
-    -DEXPAT_INCLUDE_DIR=%LODEPSDIR%\expat\include
-    -DBZIP2_LIBRARIES=%LIBBZIP2%
-    -DBZIP2_INCLUDE_DIR=%LODEPSDIR%\bzip2\include
-    -DGDAL_LIBRARY=%LODEPSDIR%\gdal\lib\gdal_i.lib
-    -DGDAL_INCLUDE_DIR=%LODEPSDIR%\gdal\include
-    -DGEOS_LIBRARY=%LODEPSDIR%\geos\lib\geos.lib
-    -DGEOS_INCLUDE_DIR=%LODEPSDIR%\geos\include
-    -DPROJ_LIBRARY=%LODEPSDIR%\proj\lib\proj.lib
-    -DPROJ_INCLUDE_DIR=%LODEPSDIR%\proj\include
-    -DSPARSEHASH_INCLUDE_DIR=%LODEPSDIR%\sparsehash\include
-    -DGETOPT_LIBRARY=%LODEPSDIR%\wingetopt\lib\wingetopt.lib
-    -DGETOPT_INCLUDE_DIR=%LODEPSDIR%\wingetopt\include
+    -DBZIP2_LIBRARY_RELEASE=%LIBBZIP2%
+    -DCMAKE_PREFIX_PATH=%LODEPSDIR%\zlib;%LODEPSDIR%\expat;%LODEPSDIR%\bzip2;%LODEPSDIR%\geos;%LODEPSDIR%\gdal;%LODEPSDIR%\proj;%LODEPSDIR%\sparsehash;%LODEPSDIR%\wingetopt
+    ..
   - msbuild libosmium.sln /p:Configuration=%config% /toolsversion:14.0 /p:Platform=x64 /p:PlatformToolset=v140
   #- cmake .. -LA -G "NMake Makefiles"
   #  -DOsmium_DEBUG=TRUE
diff --git a/cmake/FindOsmium.cmake b/cmake/FindOsmium.cmake
index bb14071..b3a4c95 100644
--- a/cmake/FindOsmium.cmake
+++ b/cmake/FindOsmium.cmake
@@ -19,7 +19,7 @@
 #    Then add the following in your CMakeLists.txt:
 #
 #      find_package(Osmium REQUIRED COMPONENTS <XXX>)
-#      include_directories(${OSMIUM_INCLUDE_DIRS})
+#      include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS})
 #
 #    For the <XXX> substitute a space separated list of one or more of the
 #    following components:
@@ -56,32 +56,12 @@ find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp
     PATH_SUFFIXES include
     PATHS
         ../libosmium
-        ../../libosmium
-        libosmium
         ~/Library/Frameworks
         /Library/Frameworks
-        /usr/local
-        /usr/
         /opt/local # DarwinPorts
         /opt
 )
 
-# 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)
-
-# Copy the results to the output variables.
-if(OSMIUM_FOUND)
-    set(OSMIUM_INCLUDE_DIRS ${OSMIUM_INCLUDE_DIR})
-else()
-    set(OSMIUM_INCLUDE_DIRS "")
-endif()
-
-if(Osmium_FIND_REQUIRED AND NOT OSMIUM_FOUND)
-    message(FATAL_ERROR "Can not find libosmium headers, please install them or configure the paths")
-endif()
-
 #----------------------------------------------------------------------
 #
 #  Check for optional components
@@ -113,6 +93,7 @@ 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}
@@ -125,7 +106,6 @@ if(Osmium_USE_PBF)
             ${ZLIB_INCLUDE_DIR}
         )
     else()
-        set(_missing_libraries 1)
         message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.")
     endif()
 endif()
@@ -138,6 +118,7 @@ if(Osmium_USE_XML)
     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}
@@ -151,7 +132,6 @@ if(Osmium_USE_XML)
             ${ZLIB_INCLUDE_DIR}
         )
     else()
-        set(_missing_libraries 1)
         message(WARNING "Osmium: Can not find some libraries for XML input/output, please install them or configure the paths.")
     endif()
 endif()
@@ -172,12 +152,12 @@ 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()
-        set(_missing_libraries 1)
         message(WARNING "Osmium: GEOS library is required but not found, please install it or configure the paths.")
     endif()
 endif()
@@ -187,11 +167,11 @@ endif()
 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()
-        set(_missing_libraries 1)
         message(WARNING "Osmium: GDAL library is required but not found, please install it or configure the paths.")
     endif()
 endif()
@@ -202,12 +182,12 @@ 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()
-        set(_missing_libraries 1)
         message(WARNING "Osmium: PROJ.4 library is required but not found, please install it or configure the paths.")
     endif()
 endif()
@@ -217,21 +197,19 @@ endif()
 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++.
-        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)
-
-        # Falling back to checking size_t if google::sparsetable<int>::size_type
-        # could not be checked.
-        if(SPARSETABLE_SIZE_TYPE STREQUAL "")
-            check_type_size("void*" VOID_PTR_SIZE)
-            set(SPARSETABLE_SIZE_TYPE ${VOID_PTR_SIZE})
+        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
@@ -244,7 +222,6 @@ if(Osmium_USE_SPARSEHASH)
             message(WARNING "Osmium: Disabled Google SparseHash library on 32bit system (size_type=${SPARSETABLE_SIZE_TYPE}).")
         endif()
     else()
-        set(_missing_libraries 1)
         message(WARNING "Osmium: Google SparseHash library is required but not found, please install it or configure the paths.")
     endif()
 endif()
@@ -274,8 +251,18 @@ endif()
 #  Check that all required libraries are available
 #
 #----------------------------------------------------------------------
-if(Osmium_FIND_REQUIRED AND _missing_libraries)
-    message(FATAL_ERROR "Required library or libraries missing. Aborting.")
+list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS)
+# 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)
+
+# Copy the results to the output variables.
+if(OSMIUM_FOUND)
+    set(OSMIUM_INCLUDE_DIRS ${OSMIUM_INCLUDE_DIR} ${OSMIUM_INCLUDE_DIRS})
+else()
+    set(OSMIUM_INCLUDE_DIRS "")
 endif()
 
 #----------------------------------------------------------------------
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index c9f5960..2ee15e1 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -17,9 +17,6 @@ set(EXAMPLES
     index
     read
     serdump
-    toogr
-    toogr2
-    toogr2_exp
     use_node_cache
     CACHE STRING "Example programs"
 )
@@ -30,7 +27,7 @@ set(EXAMPLES
 #  Examples depending on wingetopt
 #
 #-----------------------------------------------------------------------------
-set(GETOPT_EXAMPLES area_test convert serdump toogr toogr2 toogr2_exp)
+set(GETOPT_EXAMPLES area_test convert serdump)
 if(NOT GETOPT_MISSING)
     foreach(example ${GETOPT_EXAMPLES})
         list(APPEND EXAMPLE_LIBS_${example} ${GETOPT_LIBRARY})
@@ -76,27 +73,6 @@ endif()
 
 #-----------------------------------------------------------------------------
 #
-#  Examples depending on GDAL/PROJ.4/SparseHash
-#
-#-----------------------------------------------------------------------------
-set(OGR_EXAMPLES toogr toogr2 toogr2_exp)
-
-if(GDAL_FOUND AND PROJ_FOUND AND SPARSEHASH_FOUND)
-    foreach(example ${OGR_EXAMPLES})
-        list(APPEND EXAMPLE_LIBS_${example} ${GDAL_LIBRARIES})
-        list(APPEND EXAMPLE_LIBS_${example} ${PROJ_LIBRARIES})
-    endforeach()
-else()
-    message(STATUS "Configuring examples - Skipping examples because GDAL and/or Proj.4 and/or SparseHash not found:")
-    foreach(example ${OGR_EXAMPLES})
-        message(STATUS "  - osmium_${example}")
-        list(REMOVE_ITEM EXAMPLES ${example})
-    endforeach()
-endif()
-
-
-#-----------------------------------------------------------------------------
-#
 #  Configure examples
 #
 #-----------------------------------------------------------------------------
diff --git a/examples/osmium_toogr.cpp b/examples/osmium_toogr.cpp
deleted file mode 100644
index 7c5a965..0000000
--- a/examples/osmium_toogr.cpp
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
-
-  This is an example tool that converts OSM data to some output format
-  like Spatialite or Shapefiles using the OGR library.
-
-  The code in this example file is released into the Public Domain.
-
-*/
-
-#include <iostream>
-#include <getopt.h>
-
-#include <osmium/index/map/all.hpp>
-#include <osmium/handler/node_locations_for_ways.hpp>
-#include <osmium/visitor.hpp>
-
-#include <osmium/geom/ogr.hpp>
-#include <osmium/io/any_input.hpp>
-#include <osmium/handler.hpp>
-
-typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
-typedef osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
-
-typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
-
-class MyOGRHandler : public osmium::handler::Handler {
-
-    OGRDataSource* m_data_source;
-    OGRLayer* m_layer_point;
-    OGRLayer* m_layer_linestring;
-
-    osmium::geom::OGRFactory<> m_factory;
-
-public:
-
-    MyOGRHandler(const std::string& driver_name, const std::string& filename) {
-
-        OGRRegisterAll();
-
-        OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str());
-        if (!driver) {
-            std::cerr << driver_name << " driver not available.\n";
-            exit(1);
-        }
-
-        CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
-        const char* options[] = { "SPATIALITE=TRUE", nullptr };
-        m_data_source = driver->CreateDataSource(filename.c_str(), const_cast<char**>(options));
-        if (!m_data_source) {
-            std::cerr << "Creation of output file failed.\n";
-            exit(1);
-        }
-
-        OGRSpatialReference sparef;
-        sparef.SetWellKnownGeogCS("WGS84");
-        m_layer_point = m_data_source->CreateLayer("postboxes", &sparef, wkbPoint, nullptr);
-        if (!m_layer_point) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_point_field_id("id", OFTReal);
-        layer_point_field_id.SetWidth(10);
-
-        if (m_layer_point->CreateField(&layer_point_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_point_field_operator("operator", OFTString);
-        layer_point_field_operator.SetWidth(30);
-
-        if (m_layer_point->CreateField(&layer_point_field_operator) != OGRERR_NONE) {
-            std::cerr << "Creating operator field failed.\n";
-            exit(1);
-        }
-
-        /* Transactions might make things faster, then again they might not.
-           Feel free to experiment and benchmark and report back. */
-        m_layer_point->StartTransaction();
-
-        m_layer_linestring = m_data_source->CreateLayer("roads", &sparef, wkbLineString, nullptr);
-        if (!m_layer_linestring) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_linestring_field_id("id", OFTReal);
-        layer_linestring_field_id.SetWidth(10);
-
-        if (m_layer_linestring->CreateField(&layer_linestring_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_linestring_field_type("type", OFTString);
-        layer_linestring_field_type.SetWidth(30);
-
-        if (m_layer_linestring->CreateField(&layer_linestring_field_type) != OGRERR_NONE) {
-            std::cerr << "Creating type field failed.\n";
-            exit(1);
-        }
-
-        m_layer_linestring->StartTransaction();
-    }
-
-    ~MyOGRHandler() {
-        m_layer_linestring->CommitTransaction();
-        m_layer_point->CommitTransaction();
-        OGRDataSource::DestroyDataSource(m_data_source);
-        OGRCleanupAll();
-    }
-
-    void node(const osmium::Node& node) {
-        const char* amenity = node.tags().get_value_by_key("amenity");
-        if (amenity && !strcmp(amenity, "post_box")) {
-            OGRFeature* feature = OGRFeature::CreateFeature(m_layer_point->GetLayerDefn());
-            std::unique_ptr<OGRPoint> ogr_point = m_factory.create_point(node);
-            feature->SetGeometry(ogr_point.get());
-            feature->SetField("id", static_cast<double>(node.id()));
-            feature->SetField("operator", node.tags().get_value_by_key("operator"));
-
-            if (m_layer_point->CreateFeature(feature) != OGRERR_NONE) {
-                std::cerr << "Failed to create feature.\n";
-                exit(1);
-            }
-
-            OGRFeature::DestroyFeature(feature);
-        }
-    }
-
-    void way(const osmium::Way& way) {
-        const char* highway = way.tags().get_value_by_key("highway");
-        if (highway) {
-            try {
-                std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way);
-                OGRFeature* feature = OGRFeature::CreateFeature(m_layer_linestring->GetLayerDefn());
-                feature->SetGeometry(ogr_linestring.get());
-                feature->SetField("id", static_cast<double>(way.id()));
-                feature->SetField("type", highway);
-
-                if (m_layer_linestring->CreateFeature(feature) != OGRERR_NONE) {
-                    std::cerr << "Failed to create feature.\n";
-                    exit(1);
-                }
-
-                OGRFeature::DestroyFeature(feature);
-            } catch (osmium::geometry_error&) {
-                std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
-            }
-        }
-    }
-
-};
-
-/* ================================================== */
-
-void print_help() {
-    std::cout << "osmium_toogr [OPTIONS] [INFILE [OUTFILE]]\n\n" \
-              << "If INFILE is not given stdin is assumed.\n" \
-              << "If OUTFILE is not given 'ogr_out' is used.\n" \
-              << "\nOptions:\n" \
-              << "  -h, --help                 This help message\n" \
-              << "  -l, --location_store=TYPE  Set location store\n" \
-              << "  -f, --format=FORMAT        Output OGR format (Default: 'SQLite')\n" \
-              << "  -L                         See available location stores\n";
-}
-
-int main(int argc, char* argv[]) {
-    const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance();
-
-    static struct option long_options[] = {
-        {"help",                 no_argument, 0, 'h'},
-        {"format",               required_argument, 0, 'f'},
-        {"location_store",       required_argument, 0, 'l'},
-        {"list_location_stores", no_argument, 0, 'L'},
-        {0, 0, 0, 0}
-    };
-
-    std::string output_format { "SQLite" };
-    std::string location_store { "sparse_mem_array" };
-
-    while (true) {
-        int c = getopt_long(argc, argv, "hf:l:L", long_options, 0);
-        if (c == -1) {
-            break;
-        }
-
-        switch (c) {
-            case 'h':
-                print_help();
-                exit(0);
-            case 'f':
-                output_format = optarg;
-                break;
-            case 'l':
-                location_store = optarg;
-                break;
-            case 'L':
-                std::cout << "Available map types:\n";
-                for (const auto& map_type : map_factory.map_types()) {
-                    std::cout << "  " << map_type << "\n";
-                }
-                exit(0);
-            default:
-                exit(1);
-        }
-    }
-
-    std::string input_filename;
-    std::string output_filename("ogr_out");
-    int remaining_args = argc - optind;
-    if (remaining_args > 2) {
-        std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]" << std::endl;
-        exit(1);
-    } else if (remaining_args == 2) {
-        input_filename =  argv[optind];
-        output_filename = argv[optind+1];
-    } else if (remaining_args == 1) {
-        input_filename =  argv[optind];
-    } else {
-        input_filename = "-";
-    }
-
-    osmium::io::Reader reader(input_filename);
-
-    std::unique_ptr<index_pos_type> index_pos = map_factory.create_map(location_store);
-    index_neg_type index_neg;
-    location_handler_type location_handler(*index_pos, index_neg);
-    location_handler.ignore_errors();
-
-    MyOGRHandler ogr_handler(output_format, output_filename);
-
-    osmium::apply(reader, location_handler, ogr_handler);
-    reader.close();
-
-    int locations_fd = open("locations.dump", O_WRONLY | O_CREAT, 0644);
-    if (locations_fd < 0) {
-        throw std::system_error(errno, std::system_category(), "Open failed");
-    }
-    index_pos->dump_as_list(locations_fd);
-    close(locations_fd);
-}
-
diff --git a/examples/osmium_toogr2.cpp b/examples/osmium_toogr2.cpp
deleted file mode 100644
index e1b5056..0000000
--- a/examples/osmium_toogr2.cpp
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
-
-  This is an example tool that converts OSM data to some output format
-  like Spatialite or Shapefiles using the OGR library.
-
-  This version does multipolygon handling (in contrast to the osmium_toogr
-  example which doesn't).
-
-  The code in this example file is released into the Public Domain.
-
-*/
-
-#include <iostream>
-#include <getopt.h>
-
-// usually you only need one or two of these
-#include <osmium/index/map/dummy.hpp>
-#include <osmium/index/map/sparse_mem_array.hpp>
-
-#include <osmium/handler/node_locations_for_ways.hpp>
-#include <osmium/visitor.hpp>
-#include <osmium/area/multipolygon_collector.hpp>
-#include <osmium/area/assembler.hpp>
-
-#include <osmium/geom/mercator_projection.hpp>
-//#include <osmium/geom/projection.hpp>
-#include <osmium/geom/ogr.hpp>
-#include <osmium/io/any_input.hpp>
-#include <osmium/handler.hpp>
-
-typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
-
-typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
-
-typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
-
-class MyOGRHandler : public osmium::handler::Handler {
-
-    OGRDataSource* m_data_source;
-    OGRLayer* m_layer_point;
-    OGRLayer* m_layer_linestring;
-    OGRLayer* m_layer_polygon;
-
-    // Choose one of the following:
-
-    // 1. Use WGS84, do not project coordinates.
-    //osmium::geom::OGRFactory<> m_factory {};
-
-    // 2. Project coordinates into "Web Mercator".
-    osmium::geom::OGRFactory<osmium::geom::MercatorProjection> m_factory;
-
-    // 3. Use any projection that the proj library can handle.
-    //    (Initialize projection with EPSG code or proj string).
-    //    In addition you need to link with "-lproj" and add
-    //    #include <osmium/geom/projection.hpp>.
-    //osmium::geom::OGRFactory<osmium::geom::Projection> m_factory {osmium::geom::Projection(3857)};
-
-public:
-
-    MyOGRHandler(const std::string& driver_name, const std::string& filename) {
-
-        OGRRegisterAll();
-
-        OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str());
-        if (!driver) {
-            std::cerr << driver_name << " driver not available.\n";
-            exit(1);
-        }
-
-        CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
-        const char* options[] = { "SPATIALITE=TRUE", nullptr };
-        m_data_source = driver->CreateDataSource(filename.c_str(), const_cast<char**>(options));
-        if (!m_data_source) {
-            std::cerr << "Creation of output file failed.\n";
-            exit(1);
-        }
-
-        OGRSpatialReference sparef;
-        sparef.importFromProj4(m_factory.proj_string().c_str());
-
-        m_layer_point = m_data_source->CreateLayer("postboxes", &sparef, wkbPoint, nullptr);
-        if (!m_layer_point) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_point_field_id("id", OFTReal);
-        layer_point_field_id.SetWidth(10);
-
-        if (m_layer_point->CreateField(&layer_point_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_point_field_operator("operator", OFTString);
-        layer_point_field_operator.SetWidth(30);
-
-        if (m_layer_point->CreateField(&layer_point_field_operator) != OGRERR_NONE) {
-            std::cerr << "Creating operator field failed.\n";
-            exit(1);
-        }
-
-        /* Transactions might make things faster, then again they might not.
-           Feel free to experiment and benchmark and report back. */
-        m_layer_point->StartTransaction();
-
-        m_layer_linestring = m_data_source->CreateLayer("roads", &sparef, wkbLineString, nullptr);
-        if (!m_layer_linestring) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_linestring_field_id("id", OFTReal);
-        layer_linestring_field_id.SetWidth(10);
-
-        if (m_layer_linestring->CreateField(&layer_linestring_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_linestring_field_type("type", OFTString);
-        layer_linestring_field_type.SetWidth(30);
-
-        if (m_layer_linestring->CreateField(&layer_linestring_field_type) != OGRERR_NONE) {
-            std::cerr << "Creating type field failed.\n";
-            exit(1);
-        }
-
-        m_layer_linestring->StartTransaction();
-
-        m_layer_polygon = m_data_source->CreateLayer("buildings", &sparef, wkbMultiPolygon, nullptr);
-        if (!m_layer_polygon) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_polygon_field_id("id", OFTInteger);
-        layer_polygon_field_id.SetWidth(10);
-
-        if (m_layer_polygon->CreateField(&layer_polygon_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_polygon_field_type("type", OFTString);
-        layer_polygon_field_type.SetWidth(30);
-
-        if (m_layer_polygon->CreateField(&layer_polygon_field_type) != OGRERR_NONE) {
-            std::cerr << "Creating type field failed.\n";
-            exit(1);
-        }
-
-        m_layer_polygon->StartTransaction();
-    }
-
-    ~MyOGRHandler() {
-        m_layer_polygon->CommitTransaction();
-        m_layer_linestring->CommitTransaction();
-        m_layer_point->CommitTransaction();
-        OGRDataSource::DestroyDataSource(m_data_source);
-        OGRCleanupAll();
-    }
-
-    void node(const osmium::Node& node) {
-        const char* amenity = node.tags()["amenity"];
-        if (amenity && !strcmp(amenity, "post_box")) {
-            OGRFeature* feature = OGRFeature::CreateFeature(m_layer_point->GetLayerDefn());
-            std::unique_ptr<OGRPoint> ogr_point = m_factory.create_point(node);
-            feature->SetGeometry(ogr_point.get());
-            feature->SetField("id", static_cast<double>(node.id()));
-            feature->SetField("operator", node.tags()["operator"]);
-
-            if (m_layer_point->CreateFeature(feature) != OGRERR_NONE) {
-                std::cerr << "Failed to create feature.\n";
-                exit(1);
-            }
-
-            OGRFeature::DestroyFeature(feature);
-        }
-    }
-
-    void way(const osmium::Way& way) {
-        const char* highway = way.tags()["highway"];
-        if (highway) {
-            try {
-                std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way);
-                OGRFeature* feature = OGRFeature::CreateFeature(m_layer_linestring->GetLayerDefn());
-                feature->SetGeometry(ogr_linestring.get());
-                feature->SetField("id", static_cast<double>(way.id()));
-                feature->SetField("type", highway);
-
-                if (m_layer_linestring->CreateFeature(feature) != OGRERR_NONE) {
-                    std::cerr << "Failed to create feature.\n";
-                    exit(1);
-                }
-
-                OGRFeature::DestroyFeature(feature);
-            } catch (osmium::geometry_error&) {
-                std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
-            }
-        }
-    }
-
-    void area(const osmium::Area& area) {
-        const char* building = area.tags()["building"];
-        if (building) {
-            try {
-                std::unique_ptr<OGRMultiPolygon> ogr_polygon = m_factory.create_multipolygon(area);
-                OGRFeature* feature = OGRFeature::CreateFeature(m_layer_polygon->GetLayerDefn());
-                feature->SetGeometry(ogr_polygon.get());
-                feature->SetField("id", static_cast<int>(area.id()));
-                feature->SetField("type", building);
-
-                std::string type = "";
-                if (area.from_way()) {
-                    type += "w";
-                } else {
-                    type += "r";
-                }
-                feature->SetField("type", type.c_str());
-
-                if (m_layer_polygon->CreateFeature(feature) != OGRERR_NONE) {
-                    std::cerr << "Failed to create feature.\n";
-                    exit(1);
-                }
-
-                OGRFeature::DestroyFeature(feature);
-            } catch (osmium::geometry_error&) {
-                std::cerr << "Ignoring illegal geometry for area " << area.id() << " created from " << (area.from_way() ? "way" : "relation") << " with id=" << area.orig_id() << ".\n";
-            }
-        }
-    }
-
-};
-
-/* ================================================== */
-
-void print_help() {
-    std::cout << "osmium_toogr [OPTIONS] [INFILE [OUTFILE]]\n\n" \
-              << "If INFILE is not given stdin is assumed.\n" \
-              << "If OUTFILE is not given 'ogr_out' is used.\n" \
-              << "\nOptions:\n" \
-              << "  -h, --help           This help message\n" \
-              << "  -d, --debug          Enable debug output\n" \
-              << "  -f, --format=FORMAT  Output OGR format (Default: 'SQLite')\n";
-}
-
-int main(int argc, char* argv[]) {
-    static struct option long_options[] = {
-        {"help",   no_argument, 0, 'h'},
-        {"debug",  no_argument, 0, 'd'},
-        {"format", required_argument, 0, 'f'},
-        {0, 0, 0, 0}
-    };
-
-    std::string output_format("SQLite");
-    bool debug = false;
-
-    while (true) {
-        int c = getopt_long(argc, argv, "hdf:", long_options, 0);
-        if (c == -1) {
-            break;
-        }
-
-        switch (c) {
-            case 'h':
-                print_help();
-                exit(0);
-            case 'd':
-                debug = true;
-                break;
-            case 'f':
-                output_format = optarg;
-                break;
-            default:
-                exit(1);
-        }
-    }
-
-    std::string input_filename;
-    std::string output_filename("ogr_out");
-    int remaining_args = argc - optind;
-    if (remaining_args > 2) {
-        std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]" << std::endl;
-        exit(1);
-    } else if (remaining_args == 2) {
-        input_filename =  argv[optind];
-        output_filename = argv[optind+1];
-    } else if (remaining_args == 1) {
-        input_filename =  argv[optind];
-    } else {
-        input_filename = "-";
-    }
-
-    osmium::area::Assembler::config_type assembler_config;
-    assembler_config.enable_debug_output(debug);
-    osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config);
-
-    std::cerr << "Pass 1...\n";
-    osmium::io::Reader reader1(input_filename);
-    collector.read_relations(reader1);
-    reader1.close();
-    std::cerr << "Pass 1 done\n";
-
-    index_pos_type index_pos;
-    index_neg_type index_neg;
-    location_handler_type location_handler(index_pos, index_neg);
-    location_handler.ignore_errors();
-
-    MyOGRHandler ogr_handler(output_format, output_filename);
-
-    std::cerr << "Pass 2...\n";
-    osmium::io::Reader reader2(input_filename);
-
-    osmium::apply(reader2, location_handler, ogr_handler, collector.handler([&ogr_handler](const osmium::memory::Buffer& area_buffer) {
-        osmium::apply(area_buffer, ogr_handler);
-    }));
-
-    reader2.close();
-    std::cerr << "Pass 2 done\n";
-
-    std::vector<const osmium::Relation*> incomplete_relations = collector.get_incomplete_relations();
-    if (!incomplete_relations.empty()) {
-        std::cerr << "Warning! Some member ways missing for these multipolygon relations:";
-        for (const auto* relation : incomplete_relations) {
-            std::cerr << " " << relation->id();
-        }
-        std::cerr << "\n";
-    }
-}
-
diff --git a/examples/osmium_toogr2_exp.cpp b/examples/osmium_toogr2_exp.cpp
deleted file mode 100644
index db8d5cf..0000000
--- a/examples/osmium_toogr2_exp.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
-
-  This is an example tool that converts OSM data to some output format
-  like Spatialite or Shapefiles using the OGR library.
-
-  This version does multipolygon handling (in contrast to the osmium_toogr
-  example which doesn't).
-
-  This version (..._exp) uses a new experimental unsupported interface.
-
-  The code in this example file is released into the Public Domain.
-
-*/
-
-#include <iostream>
-#include <getopt.h>
-
-#include <osmium/index/map/sparse_mem_array.hpp>
-
-#include <osmium/visitor.hpp>
-
-#include <osmium/geom/mercator_projection.hpp>
-//#include <osmium/geom/projection.hpp>
-#include <osmium/geom/ogr.hpp>
-#include <osmium/io/any_input.hpp>
-#include <osmium/handler.hpp>
-#include <osmium/experimental/flex_reader.hpp>
-
-typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
-typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type;
-
-class MyOGRHandler : public osmium::handler::Handler {
-
-    OGRDataSource* m_data_source;
-    OGRLayer* m_layer_point;
-    OGRLayer* m_layer_linestring;
-    OGRLayer* m_layer_polygon;
-
-    // Choose one of the following:
-
-    // 1. Use WGS84, do not project coordinates.
-    //osmium::geom::OGRFactory<> m_factory {};
-
-    // 2. Project coordinates into "Web Mercator".
-    osmium::geom::OGRFactory<osmium::geom::MercatorProjection> m_factory;
-
-    // 3. Use any projection that the proj library can handle.
-    //    (Initialize projection with EPSG code or proj string).
-    //    In addition you need to link with "-lproj" and add
-    //    #include <osmium/geom/projection.hpp>.
-    //osmium::geom::OGRFactory<osmium::geom::Projection> m_factory {osmium::geom::Projection(3857)};
-
-public:
-
-    MyOGRHandler(const std::string& driver_name, const std::string& filename) {
-
-        OGRRegisterAll();
-
-        OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str());
-        if (!driver) {
-            std::cerr << driver_name << " driver not available.\n";
-            exit(1);
-        }
-
-        CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
-        const char* options[] = { "SPATIALITE=TRUE", nullptr };
-        m_data_source = driver->CreateDataSource(filename.c_str(), const_cast<char**>(options));
-        if (!m_data_source) {
-            std::cerr << "Creation of output file failed.\n";
-            exit(1);
-        }
-
-        OGRSpatialReference sparef;
-        sparef.importFromProj4(m_factory.proj_string().c_str());
-
-        m_layer_point = m_data_source->CreateLayer("postboxes", &sparef, wkbPoint, nullptr);
-        if (!m_layer_point) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_point_field_id("id", OFTReal);
-        layer_point_field_id.SetWidth(10);
-
-        if (m_layer_point->CreateField(&layer_point_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_point_field_operator("operator", OFTString);
-        layer_point_field_operator.SetWidth(30);
-
-        if (m_layer_point->CreateField(&layer_point_field_operator) != OGRERR_NONE) {
-            std::cerr << "Creating operator field failed.\n";
-            exit(1);
-        }
-
-        /* Transactions might make things faster, then again they might not.
-           Feel free to experiment and benchmark and report back. */
-        m_layer_point->StartTransaction();
-
-        m_layer_linestring = m_data_source->CreateLayer("roads", &sparef, wkbLineString, nullptr);
-        if (!m_layer_linestring) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_linestring_field_id("id", OFTReal);
-        layer_linestring_field_id.SetWidth(10);
-
-        if (m_layer_linestring->CreateField(&layer_linestring_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_linestring_field_type("type", OFTString);
-        layer_linestring_field_type.SetWidth(30);
-
-        if (m_layer_linestring->CreateField(&layer_linestring_field_type) != OGRERR_NONE) {
-            std::cerr << "Creating type field failed.\n";
-            exit(1);
-        }
-
-        m_layer_linestring->StartTransaction();
-
-        m_layer_polygon = m_data_source->CreateLayer("buildings", &sparef, wkbMultiPolygon, nullptr);
-        if (!m_layer_polygon) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_polygon_field_id("id", OFTInteger);
-        layer_polygon_field_id.SetWidth(10);
-
-        if (m_layer_polygon->CreateField(&layer_polygon_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_polygon_field_type("type", OFTString);
-        layer_polygon_field_type.SetWidth(30);
-
-        if (m_layer_polygon->CreateField(&layer_polygon_field_type) != OGRERR_NONE) {
-            std::cerr << "Creating type field failed.\n";
-            exit(1);
-        }
-
-        m_layer_polygon->StartTransaction();
-    }
-
-    ~MyOGRHandler() {
-        m_layer_polygon->CommitTransaction();
-        m_layer_linestring->CommitTransaction();
-        m_layer_point->CommitTransaction();
-        OGRDataSource::DestroyDataSource(m_data_source);
-        OGRCleanupAll();
-    }
-
-    void node(const osmium::Node& node) {
-        const char* amenity = node.tags()["amenity"];
-        if (amenity && !strcmp(amenity, "post_box")) {
-            OGRFeature* feature = OGRFeature::CreateFeature(m_layer_point->GetLayerDefn());
-            std::unique_ptr<OGRPoint> ogr_point = m_factory.create_point(node);
-            feature->SetGeometry(ogr_point.get());
-            feature->SetField("id", static_cast<double>(node.id()));
-            feature->SetField("operator", node.tags()["operator"]);
-
-            if (m_layer_point->CreateFeature(feature) != OGRERR_NONE) {
-                std::cerr << "Failed to create feature.\n";
-                exit(1);
-            }
-
-            OGRFeature::DestroyFeature(feature);
-        }
-    }
-
-    void way(const osmium::Way& way) {
-        const char* highway = way.tags()["highway"];
-        if (highway) {
-            try {
-                std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way);
-                OGRFeature* feature = OGRFeature::CreateFeature(m_layer_linestring->GetLayerDefn());
-                feature->SetGeometry(ogr_linestring.get());
-                feature->SetField("id", static_cast<double>(way.id()));
-                feature->SetField("type", highway);
-
-                if (m_layer_linestring->CreateFeature(feature) != OGRERR_NONE) {
-                    std::cerr << "Failed to create feature.\n";
-                    exit(1);
-                }
-
-                OGRFeature::DestroyFeature(feature);
-            } catch (osmium::geometry_error&) {
-                std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
-            }
-        }
-    }
-
-    void area(const osmium::Area& area) {
-        const char* building = area.tags()["building"];
-        if (building) {
-            try {
-                std::unique_ptr<OGRMultiPolygon> ogr_polygon = m_factory.create_multipolygon(area);
-                OGRFeature* feature = OGRFeature::CreateFeature(m_layer_polygon->GetLayerDefn());
-                feature->SetGeometry(ogr_polygon.get());
-                feature->SetField("id", static_cast<int>(area.id()));
-                feature->SetField("type", building);
-
-                std::string type = "";
-                if (area.from_way()) {
-                    type += "w";
-                } else {
-                    type += "r";
-                }
-                feature->SetField("type", type.c_str());
-
-                if (m_layer_polygon->CreateFeature(feature) != OGRERR_NONE) {
-                    std::cerr << "Failed to create feature.\n";
-                    exit(1);
-                }
-
-                OGRFeature::DestroyFeature(feature);
-            } catch (osmium::geometry_error&) {
-                std::cerr << "Ignoring illegal geometry for area " << area.id() << " created from " << (area.from_way() ? "way" : "relation") << " with id=" << area.orig_id() << ".\n";
-            }
-        }
-    }
-
-};
-
-/* ================================================== */
-
-void print_help() {
-    std::cout << "osmium_toogr [OPTIONS] [INFILE [OUTFILE]]\n\n" \
-              << "If INFILE is not given stdin is assumed.\n" \
-              << "If OUTFILE is not given 'ogr_out' is used.\n" \
-              << "\nOptions:\n" \
-              << "  -h, --help           This help message\n" \
-              << "  -f, --format=FORMAT  Output OGR format (Default: 'SQLite')\n";
-}
-
-int main(int argc, char* argv[]) {
-    static struct option long_options[] = {
-        {"help",   no_argument, 0, 'h'},
-        {"format", required_argument, 0, 'f'},
-        {0, 0, 0, 0}
-    };
-
-    std::string output_format("SQLite");
-
-    while (true) {
-        int c = getopt_long(argc, argv, "hf:", long_options, 0);
-        if (c == -1) {
-            break;
-        }
-
-        switch (c) {
-            case 'h':
-                print_help();
-                exit(0);
-            case 'f':
-                output_format = optarg;
-                break;
-            default:
-                exit(1);
-        }
-    }
-
-    std::string input_filename;
-    std::string output_filename("ogr_out");
-    int remaining_args = argc - optind;
-    if (remaining_args > 2) {
-        std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]" << std::endl;
-        exit(1);
-    } else if (remaining_args == 2) {
-        input_filename =  argv[optind];
-        output_filename = argv[optind+1];
-    } else if (remaining_args == 1) {
-        input_filename =  argv[optind];
-    } else {
-        input_filename = "-";
-    }
-
-    index_type index_pos;
-    location_handler_type location_handler(index_pos);
-    osmium::experimental::FlexReader<location_handler_type> exr(input_filename, location_handler, osmium::osm_entity_bits::object);
-
-    MyOGRHandler ogr_handler(output_format, output_filename);
-
-    while (auto buffer = exr.read()) {
-        osmium::apply(buffer, ogr_handler);
-    }
-
-    exr.close();
-
-    std::vector<const osmium::Relation*> incomplete_relations = exr.collector().get_incomplete_relations();
-    if (!incomplete_relations.empty()) {
-        std::cerr << "Warning! Some member ways missing for these multipolygon relations:";
-        for (const auto* relation : incomplete_relations) {
-            std::cerr << " " << relation->id();
-        }
-        std::cerr << "\n";
-    }
-}
-
diff --git a/include/gdalcpp.hpp b/include/gdalcpp.hpp
new file mode 100644
index 0000000..a66e1ea
--- /dev/null
+++ b/include/gdalcpp.hpp
@@ -0,0 +1,302 @@
+#ifndef GDALCPP_HPP
+#define GDALCPP_HPP
+
+/*
+
+C++11 wrapper classes for GDAL/OGR.
+
+Version 1.0.0
+
+https://github.com/joto/gdalcpp
+
+Copyright 2015 Jochen Topf <jochen at topf.org>
+
+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>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include <gdal_priv.h>
+#include <gdal_version.h>
+#include <ogr_api.h>
+#include <ogrsf_frmts.h>
+
+namespace gdalcpp {
+
+#if GDAL_VERSION_MAJOR >= 2
+    typedef GDALDriver gdal_driver_type;
+    typedef GDALDataset gdal_dataset_type;
+#else
+    typedef OGRSFDriver gdal_driver_type;
+    typedef OGRDataSource gdal_dataset_type;
+#endif
+
+    class gdal_error : public std::runtime_error {
+
+        std::string m_driver;
+        std::string m_dataset;
+        std::string m_layer;
+        std::string m_field;
+
+    public:
+
+        gdal_error(const std::string& message,
+                   const std::string& driver = "",
+                   const std::string& dataset = "",
+                   const std::string& layer = "",
+                   const std::string& field = "") :
+            std::runtime_error(message),
+            m_driver(driver),
+            m_dataset(dataset),
+            m_layer(layer),
+            m_field(field) {
+        }
+
+        const std::string& driver() const {
+            return m_driver;
+        }
+
+        const std::string& dataset() const {
+            return m_dataset;
+        }
+
+        const std::string& layer() const {
+            return m_layer;
+        }
+
+        const std::string& field() const {
+            return m_field;
+        }
+
+    }; // class gdal_error
+
+    namespace detail {
+
+        struct init_wrapper {
+            init_wrapper() { OGRRegisterAll(); }
+            ~init_wrapper() { OGRCleanupAll(); }
+        };
+
+        struct init_library {
+            init_library() {
+                static init_wrapper iw;
+            }
+        };
+
+        class Driver : private init_library {
+
+            gdal_driver_type* m_driver;
+
+        public:
+
+            Driver(const std::string& driver_name) :
+                init_library(),
+                m_driver(OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str())) {
+                if (!m_driver) {
+                    throw gdal_error(std::string("unknown driver: '") + driver_name + "'", driver_name);
+                }
+            }
+
+            gdal_driver_type& get() const {
+                return *m_driver;
+            }
+
+        }; // struct Driver
+
+        struct Options {
+
+            std::vector<std::string> m_options;
+            std::unique_ptr<const char*[]> m_ptrs;
+
+            Options(const std::vector<std::string>& options) :
+                m_options(options),
+                m_ptrs(new const char*[options.size()+1]) {
+                std::transform(m_options.begin(), m_options.end(), m_ptrs.get(), [&](const std::string& s) {
+                    return s.data();
+                });
+                m_ptrs[options.size()] = nullptr;
+            }
+
+            char** get() const {
+                return const_cast<char**>(m_ptrs.get());
+            }
+
+        }; // struct Options
+
+    } // namespace detail
+
+    class Dataset {
+
+        struct gdal_dataset_deleter {
+
+            void operator()(gdal_dataset_type* ds) {
+#if GDAL_VERSION_MAJOR >= 2
+                GDALClose(ds);
+#else
+                OGRDataSource::DestroyDataSource(ds);
+#endif
+            }
+
+        }; // struct gdal_dataset_deleter
+
+        std::string m_driver_name;
+        std::string m_dataset_name;
+        detail::Options m_options;
+        std::unique_ptr<gdal_dataset_type, gdal_dataset_deleter> m_dataset;
+        OGRSpatialReference m_spatial_reference;
+
+    public:
+
+        Dataset(const std::string& driver_name, const std::string& dataset_name, const std::string& proj = "", const std::vector<std::string>& options = {}) :
+            m_driver_name(driver_name),
+            m_dataset_name(dataset_name),
+            m_options(options),
+#if GDAL_VERSION_MAJOR >= 2
+            m_dataset(detail::Driver(driver_name).get().Create(dataset_name.c_str(), 0, 0, 0, GDT_Unknown, m_options.get())) {
+#else
+            m_dataset(detail::Driver(driver_name).get().CreateDataSource(dataset_name.c_str(), m_options.get())) {
+#endif
+            if (!m_dataset) {
+                throw gdal_error(std::string("failed to create dataset '") + dataset_name + "'", driver_name, dataset_name);
+            }
+            if (proj.empty()) {
+                m_spatial_reference.SetWellKnownGeogCS("WGS84");
+            } else {
+                m_spatial_reference.importFromProj4(proj.c_str());
+            }
+        }
+
+        const std::string& driver_name() const {
+            return m_driver_name;
+        }
+
+        const std::string& dataset_name() const {
+            return m_dataset_name;
+        }
+
+        gdal_dataset_type& get() const {
+            return *m_dataset;
+        }
+
+        OGRSpatialReference* spatial_reference() {
+            return &m_spatial_reference;
+        }
+
+        Dataset& start_transaction() {
+#if GDAL_VERSION_MAJOR >= 2
+            m_dataset->StartTransaction();
+#endif
+            return *this;
+        }
+
+        Dataset& commit_transaction() {
+#if GDAL_VERSION_MAJOR >= 2
+            m_dataset->CommitTransaction();
+#endif
+            return *this;
+        }
+
+    }; // class Dataset
+
+    class Layer {
+
+        Dataset& m_dataset;
+        OGRLayer* m_layer;
+
+    public:
+
+        Layer(Dataset& dataset, const std::string& layer_name, OGRwkbGeometryType type) :
+            m_dataset(dataset),
+            m_layer(dataset.get().CreateLayer(layer_name.c_str(), dataset.spatial_reference(), type)) {
+            if (!m_layer) {
+                throw gdal_error(std::string("failed to create layer '") + layer_name + "'",
+                    dataset.driver_name(), dataset.dataset_name(), layer_name);
+            }
+        }
+
+        OGRLayer* get() const {
+            return m_layer;
+        }
+
+        const char* name() {
+            return m_layer->GetName();
+        }
+
+        Layer& add_field(const std::string& field_name, OGRFieldType type, int width, int precision=0) {
+            OGRFieldDefn field(field_name.c_str(), type);
+            field.SetWidth(width);
+            field.SetPrecision(precision);
+
+            if (m_layer->CreateField(&field) != OGRERR_NONE) {
+                throw gdal_error(std::string("failed to create field '") + field_name + "' in layer '" + name() + "'",
+                    m_dataset.driver_name(), m_dataset.dataset_name(), name(), field_name);
+            }
+
+            return *this;
+        }
+
+    }; // class Layer
+
+    class Feature {
+
+        OGRLayer* m_layer;
+        OGRFeature m_feature;
+
+    public:
+
+        Feature(Layer& layer, std::unique_ptr<OGRGeometry>&& geometry) :
+            m_layer(layer.get()),
+            m_feature(m_layer->GetLayerDefn()) {
+            m_feature.SetGeometry(geometry.get());
+        }
+
+        void add_to_layer() {
+            if (m_layer->CreateFeature(&m_feature) != OGRERR_NONE) {
+                std::runtime_error("feature creation failed");
+            }
+        }
+
+        template <class T>
+        Feature& set_field(int n, T&& arg) {
+            m_feature.SetField(n, std::forward<T>(arg));
+            return *this;
+        }
+
+        template <class T>
+        Feature& set_field(const char* name, T&& arg) {
+            m_feature.SetField(name, std::forward<T>(arg));
+            return *this;
+        }
+
+    }; // class Feature
+
+} // namespace gdalcpp
+
+#endif // GDALCPP_HPP
diff --git a/include/osmium/area/problem_reporter_ogr.hpp b/include/osmium/area/problem_reporter_ogr.hpp
index c437a3f..d98a5b2 100644
--- a/include/osmium/area/problem_reporter_ogr.hpp
+++ b/include/osmium/area/problem_reporter_ogr.hpp
@@ -42,33 +42,11 @@ DEALINGS IN THE SOFTWARE.
  * @attention If you include this file, you'll need to link with `libgdal`.
  */
 
-#ifdef _MSC_VER
-# pragma warning(push)
-# pragma warning(disable : 4458)
-#else
-# pragma GCC diagnostic push
-# ifdef __clang__
-#  pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
-# endif
-# pragma GCC diagnostic ignored "-Wfloat-equal"
-# pragma GCC diagnostic ignored "-Wold-style-cast"
-# pragma GCC diagnostic ignored "-Wpadded"
-# pragma GCC diagnostic ignored "-Wredundant-decls"
-# pragma GCC diagnostic ignored "-Wshadow"
-#endif
-
-#include <ogr_api.h>
-#include <ogrsf_frmts.h>
-
-#ifdef _MSC_VER
-# pragma warning(pop)
-#else
-# pragma GCC diagnostic pop
-#endif
-
 #include <memory>
 #include <stdexcept>
 
+#include <gdalcpp.hpp>
+
 #include <osmium/area/problem_reporter.hpp>
 #include <osmium/geom/ogr.hpp>
 #include <osmium/osm/location.hpp>
@@ -86,24 +64,15 @@ namespace osmium {
 
             osmium::geom::OGRFactory<> m_ogr_factory;
 
-            OGRDataSource* m_data_source;
-
-            OGRLayer* m_layer_perror;
-            OGRLayer* m_layer_lerror;
+            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) {
-                OGRFeature* feature = OGRFeature::CreateFeature(m_layer_perror->GetLayerDefn());
-                std::unique_ptr<OGRPoint> ogr_point = m_ogr_factory.create_point(location);
-                feature->SetGeometry(ogr_point.get());
-                feature->SetField("id1", static_cast<double>(id1));
-                feature->SetField("id2", static_cast<double>(id2));
-                feature->SetField("problem_type", problem_type);
-
-                if (m_layer_perror->CreateFeature(feature) != OGRERR_NONE) {
-                    std::runtime_error("Failed to create feature on layer 'perrors'");
-                }
-
-                OGRFeature::DestroyFeature(feature);
+                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) {
@@ -112,80 +81,27 @@ namespace osmium {
                 std::unique_ptr<OGRLineString> ogr_linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
                 ogr_linestring->addPoint(ogr_point1.get());
                 ogr_linestring->addPoint(ogr_point2.get());
-                OGRFeature* feature = OGRFeature::CreateFeature(m_layer_lerror->GetLayerDefn());
-                feature->SetGeometry(ogr_linestring.get());
-                feature->SetField("id1", static_cast<double>(id1));
-                feature->SetField("id2", static_cast<double>(id2));
-                feature->SetField("problem_type", problem_type);
 
-                if (m_layer_lerror->CreateFeature(feature) != OGRERR_NONE) {
-                    std::runtime_error("Failed to create feature on layer 'lerrors'");
-                }
-
-                OGRFeature::DestroyFeature(feature);
+                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(OGRDataSource* data_source) :
-                m_data_source(data_source) {
-
-                OGRSpatialReference sparef;
-                sparef.SetWellKnownGeogCS("WGS84");
-
-                m_layer_perror = m_data_source->CreateLayer("perrors", &sparef, wkbPoint, nullptr);
-                if (!m_layer_perror) {
-                    std::runtime_error("Layer creation failed for layer 'perrors'");
-                }
-
-                OGRFieldDefn layer_perror_field_id1("id1", OFTReal);
-                layer_perror_field_id1.SetWidth(10);
-
-                if (m_layer_perror->CreateField(&layer_perror_field_id1) != OGRERR_NONE) {
-                    std::runtime_error("Creating field 'id1' failed for layer 'perrors'");
-                }
-
-                OGRFieldDefn layer_perror_field_id2("id2", OFTReal);
-                layer_perror_field_id2.SetWidth(10);
-
-                if (m_layer_perror->CreateField(&layer_perror_field_id2) != OGRERR_NONE) {
-                    std::runtime_error("Creating field 'id2' failed for layer 'perrors'");
-                }
-
-                OGRFieldDefn layer_perror_field_problem_type("problem_type", OFTString);
-                layer_perror_field_problem_type.SetWidth(30);
-
-                if (m_layer_perror->CreateField(&layer_perror_field_problem_type) != OGRERR_NONE) {
-                    std::runtime_error("Creating field 'problem_type' failed for layer 'perrors'");
-                }
-
-                /**************/
-
-                m_layer_lerror = m_data_source->CreateLayer("lerrors", &sparef, wkbLineString, nullptr);
-                if (!m_layer_lerror) {
-                    std::runtime_error("Layer creation failed for layer 'lerrors'");
-                }
-
-                OGRFieldDefn layer_lerror_field_id1("id1", OFTReal);
-                layer_lerror_field_id1.SetWidth(10);
-
-                if (m_layer_lerror->CreateField(&layer_lerror_field_id1) != OGRERR_NONE) {
-                    std::runtime_error("Creating field 'id1' failed for layer 'lerrors'");
-                }
-
-                OGRFieldDefn layer_lerror_field_id2("id2", OFTReal);
-                layer_lerror_field_id2.SetWidth(10);
-
-                if (m_layer_lerror->CreateField(&layer_lerror_field_id2) != OGRERR_NONE) {
-                    std::runtime_error("Creating field 'id2' failed for layer 'lerrors'");
-                }
+            explicit ProblemReporterOGR(gdalcpp::Dataset& dataset) :
+                m_layer_perror(dataset, "perrors", wkbPoint),
+                m_layer_lerror(dataset, "lerrors", wkbLineString) {
 
-                OGRFieldDefn layer_lerror_field_problem_type("problem_type", OFTString);
-                layer_lerror_field_problem_type.SetWidth(30);
+                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);
 
-                if (m_layer_lerror->CreateField(&layer_lerror_field_problem_type) != OGRERR_NONE) {
-                    std::runtime_error("Creating field 'problem_type' failed for layer 'lerrors'");
-                }
+                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;
diff --git a/include/osmium/builder/osm_object_builder.hpp b/include/osmium/builder/osm_object_builder.hpp
index 074076c..5827243 100644
--- a/include/osmium/builder/osm_object_builder.hpp
+++ b/include/osmium/builder/osm_object_builder.hpp
@@ -76,6 +76,12 @@ namespace osmium {
              * @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));
             }
 
@@ -87,8 +93,15 @@ namespace osmium {
              * @param value Pointer to tag value.
              * @param value_length Length of value (not including the \0 byte).
              */
-            void add_tag(const char* key, const string_size_type key_length, const char* value, const string_size_type value_length) {
-                add_size(append(key, key_length) + append_zero() + append(value, value_length) + append_zero());
+            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());
             }
 
             /**
@@ -98,8 +111,14 @@ namespace osmium {
              * @param value Tag value.
              */
             void add_tag(const std::string& key, const std::string& value) {
-                add_size(append(key.data(),   static_cast_with_assert<string_size_type>(key.size()   + 1)) +
-                         append(value.data(), static_cast_with_assert<string_size_type>(value.size() + 1)));
+                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
@@ -141,35 +160,17 @@ namespace osmium {
              *               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 string_size_type length) {
-                member.set_role_size(length + 1);
-                add_size(append(role, length) + append_zero());
+            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);
             }
 
-            /**
-             * Add role to buffer.
-             *
-             * @param member Relation member object where the length of the role
-             *               will be set.
-             * @param role \0-terminated role.
-             */
-            void add_role(osmium::RelationMember& member, const char* role) {
-                add_role(member, role, static_cast_with_assert<string_size_type>(std::strlen(role)));
-            }
-
-            /**
-             * Add role to buffer.
-             *
-             * @param member Relation member object where the length of the role
-             *               will be set.
-             * @param role Role.
-             */
-            void add_role(osmium::RelationMember& member, const std::string& role) {
-                add_role(member, role.data(), static_cast_with_assert<string_size_type>(role.size()));
-            }
-
         public:
 
             explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
@@ -190,8 +191,10 @@ namespace osmium {
              * @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 string_size_type role_length, const osmium::OSMObject* full_member = nullptr) {
+            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));
@@ -210,9 +213,10 @@ namespace osmium {
              * @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, strlen(role), full_member);
+                add_member(type, ref, role, std::strlen(role), full_member);
             }
 
             /**
@@ -224,6 +228,7 @@ namespace osmium {
              * @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);
diff --git a/include/osmium/geom/factory.hpp b/include/osmium/geom/factory.hpp
index 9be050d..13e5955 100644
--- a/include/osmium/geom/factory.hpp
+++ b/include/osmium/geom/factory.hpp
@@ -182,6 +182,7 @@ namespace osmium {
                 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;
diff --git a/include/osmium/geom/ogr.hpp b/include/osmium/geom/ogr.hpp
index f33971c..7f726ed 100644
--- a/include/osmium/geom/ogr.hpp
+++ b/include/osmium/geom/ogr.hpp
@@ -47,35 +47,7 @@ DEALINGS IN THE SOFTWARE.
 #include <memory>
 #include <utility>
 
-#ifdef _MSC_VER
-# pragma warning(push)
-# pragma warning(disable : 4458)
-# pragma warning(disable : 4251)
-#else
-# pragma GCC diagnostic push
-# ifdef __clang__
-#  pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
-# endif
-# pragma GCC diagnostic ignored "-Wfloat-equal"
-# pragma GCC diagnostic ignored "-Wold-style-cast"
-# pragma GCC diagnostic ignored "-Wpadded"
-# pragma GCC diagnostic ignored "-Wredundant-decls"
-# pragma GCC diagnostic ignored "-Wshadow"
-#endif
-
-/* Strictly speaking the following include would be enough here,
-   but everybody using this file will very likely need the other includes,
-   so we are adding them here, so that not everybody will need all those
-   pragmas to disable warnings. */
-//#include <ogr_geometry.h>
-#include <ogr_api.h>
-#include <ogrsf_frmts.h>
-
-#ifdef _MSC_VER
-# pragma warning(pop)
-#else
-# pragma GCC diagnostic pop
-#endif
+#include <ogr_geometry.h>
 
 #include <osmium/geom/coordinates.hpp>
 #include <osmium/geom/factory.hpp>
diff --git a/include/osmium/geom/tile.hpp b/include/osmium/geom/tile.hpp
index 9cd0b28..1392480 100644
--- a/include/osmium/geom/tile.hpp
+++ b/include/osmium/geom/tile.hpp
@@ -69,8 +69,8 @@ namespace osmium {
                 osmium::geom::Coordinates c = lonlat_to_mercator(location);
                 const int32_t n = 1LL << zoom;
                 const double scale = detail::max_coordinate_epsg3857 * 2 / n;
-                x = detail::restrict_to_range<int32_t>((c.x + detail::max_coordinate_epsg3857) / scale, 0, n-1);
-                y = detail::restrict_to_range<int32_t>((detail::max_coordinate_epsg3857 - c.y) / scale, 0, n-1);
+                x = detail::restrict_to_range<int32_t>(int32_t((c.x + detail::max_coordinate_epsg3857) / scale), 0, n-1);
+                y = detail::restrict_to_range<int32_t>(int32_t((detail::max_coordinate_epsg3857 - c.y) / scale), 0, n-1);
             }
 
         }; // struct Tile
diff --git a/include/osmium/io/detail/debug_output_format.hpp b/include/osmium/io/detail/debug_output_format.hpp
index efecc58..026cdc3 100644
--- a/include/osmium/io/detail/debug_output_format.hpp
+++ b/include/osmium/io/detail/debug_output_format.hpp
@@ -211,14 +211,14 @@ namespace osmium {
                         *m_out += padding;
                         output_formatted("     %d\n", tags.size());
 
-                        osmium::max_op<int> max;
+                        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());
-                            int spacing = max() - std::strlen(tag.key());
+                            auto spacing = max() - std::strlen(tag.key());
                             while (spacing--) {
                                 *m_out += " ";
                             }
diff --git a/include/osmium/io/detail/input_format.hpp b/include/osmium/io/detail/input_format.hpp
index 03e1190..743845c 100644
--- a/include/osmium/io/detail/input_format.hpp
+++ b/include/osmium/io/detail/input_format.hpp
@@ -136,15 +136,12 @@ namespace osmium {
                     return true;
                 }
 
-                std::unique_ptr<osmium::io::detail::InputFormat> create_input(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) {
-                    file.check();
-
+                create_input_type* get_creator_function(const osmium::io::File& file) {
                     auto it = m_callbacks.find(file.format());
-                    if (it != m_callbacks.end()) {
-                        return std::unique_ptr<osmium::io::detail::InputFormat>((it->second)(file, read_which_entities, input_queue));
+                    if (it == m_callbacks.end()) {
+                        throw std::runtime_error(std::string("Can not open file '") + file.filename() + "' with type '" + as_string(file.format()) + "'. No support for reading this format in this program.");
                     }
-
-                    throw std::runtime_error(std::string("Support for input format '") + as_string(file.format()) + "' not compiled into this binary.");
+                    return &(it->second);
                 }
 
             }; // class InputFormatFactory
diff --git a/include/osmium/io/detail/output_format.hpp b/include/osmium/io/detail/output_format.hpp
index 529a189..ed48b38 100644
--- a/include/osmium/io/detail/output_format.hpp
+++ b/include/osmium/io/detail/output_format.hpp
@@ -135,14 +135,12 @@ namespace osmium {
                 }
 
                 std::unique_ptr<osmium::io::detail::OutputFormat> create_output(const osmium::io::File& file, data_queue_type& output_queue) {
-                    file.check();
-
                     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 std::runtime_error(std::string("Support for output format '") + as_string(file.format()) + "' not compiled into this binary.");
+                    throw std::runtime_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
diff --git a/include/osmium/io/detail/pbf_decoder.hpp b/include/osmium/io/detail/pbf_decoder.hpp
index 79e899f..e9e0e82 100644
--- a/include/osmium/io/detail/pbf_decoder.hpp
+++ b/include/osmium/io/detail/pbf_decoder.hpp
@@ -62,13 +62,14 @@ namespace osmium {
         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<ptr_len_type> m_stringtable;
+                std::vector<osm_string_len_type> m_stringtable;
 
                 int64_t m_lon_offset = 0;
                 int64_t m_lat_offset = 0;
@@ -86,7 +87,11 @@ namespace osmium {
 
                     protozero::pbf_message<OSMFormat::StringTable> pbf_string_table(data);
                     while (pbf_string_table.next(OSMFormat::StringTable::repeated_bytes_s)) {
-                        m_stringtable.push_back(pbf_string_table.get_data());
+                        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));
                     }
                 }
 
@@ -156,8 +161,8 @@ namespace osmium {
                     }
                 }
 
-                ptr_len_type decode_info(const ptr_len_type& data, osmium::OSMObject& object) {
-                    ptr_len_type user = std::make_pair("", 0);
+                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()) {
@@ -220,7 +225,7 @@ namespace osmium {
                 }
 
                 int32_t convert_pbf_coordinate(int64_t c) const {
-                    return (c * m_granularity + m_lon_offset) / resolution_convert;
+                    return int32_t((c * m_granularity + m_lon_offset) / resolution_convert);
                 }
 
                 void decode_node(const ptr_len_type& data) {
@@ -232,7 +237,7 @@ namespace osmium {
                     int64_t lon = std::numeric_limits<int64_t>::max();
                     int64_t lat = std::numeric_limits<int64_t>::max();
 
-                    ptr_len_type user = { "", 0 };
+                    osm_string_len_type user = { "", 0 };
 
                     protozero::pbf_message<OSMFormat::Node> pbf_node(data);
                     while (pbf_node.next()) {
@@ -285,7 +290,7 @@ namespace osmium {
                     kv_type vals;
                     std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> refs;
 
-                    ptr_len_type user = { "", 0 };
+                    osm_string_len_type user = { "", 0 };
 
                     protozero::pbf_message<OSMFormat::Way> pbf_way(data);
                     while (pbf_way.next()) {
@@ -334,7 +339,7 @@ namespace osmium {
                     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;
 
-                    ptr_len_type user = { "", 0 };
+                    osm_string_len_type user = { "", 0 };
 
                     protozero::pbf_message<OSMFormat::Relation> pbf_relation(data);
                     while (pbf_relation.next()) {
@@ -512,7 +517,7 @@ namespace osmium {
                                     // this is against the spec, must have same number of elements
                                     throw osmium::pbf_error("PBF format error");
                                 }
-                                visible = *visibles.first++;
+                                visible = (*visibles.first++) != 0;
                             }
                             node.set_visible(visible);
 
@@ -579,8 +584,8 @@ namespace osmium {
             }; // class PBFPrimitiveBlockDecoder
 
             inline ptr_len_type decode_blob(const std::string& blob_data, std::string& output) {
-                int32_t raw_size;
-                std::pair<const char*, protozero::pbf_length_type> zlib_data;
+                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()) {
@@ -609,7 +614,7 @@ namespace osmium {
                     }
                 }
 
-                if (zlib_data.second != 0) {
+                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),
diff --git a/include/osmium/io/detail/pbf_output_format.hpp b/include/osmium/io/detail/pbf_output_format.hpp
index 8d8a079..9098b47 100644
--- a/include/osmium/io/detail/pbf_output_format.hpp
+++ b/include/osmium/io/detail/pbf_output_format.hpp
@@ -47,6 +47,8 @@ DEALINGS IN THE SOFTWARE.
 #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>
@@ -113,11 +115,13 @@ namespace osmium {
              * @param use_compression Should the output be compressed using zlib?
              */
             inline std::string serialize_blob(const std::string& type, const std::string& msg, bool use_compression) {
+                assert(msg.size() <= max_uncompressed_blob_size);
+
                 std::string blob_data;
                 protozero::pbf_builder<FileFormat::Blob> pbf_blob(blob_data);
 
                 if (use_compression) {
-                    pbf_blob.add_int32(FileFormat::Blob::optional_int32_raw_size, msg.size());
+                    pbf_blob.add_int32(FileFormat::Blob::optional_int32_raw_size, int32_t(msg.size()));
                     pbf_blob.add_bytes(FileFormat::Blob::optional_bytes_zlib_data, osmium::io::detail::zlib_compress(msg));
                 } else {
                     pbf_blob.add_bytes(FileFormat::Blob::optional_bytes_raw, msg);
@@ -127,7 +131,7 @@ namespace osmium {
                 protozero::pbf_builder<FileFormat::BlobHeader> pbf_blob_header(blob_header_data);
 
                 pbf_blob_header.add_string(FileFormat::BlobHeader::required_string_type, type);
-                pbf_blob_header.add_int32(FileFormat::BlobHeader::required_int32_datasize, blob_data.size());
+                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()));
 
@@ -312,7 +316,7 @@ namespace osmium {
                     ++m_count;
                 }
 
-                size_t add_string(const char* s) {
+                uint32_t store_in_stringtable(const char* s) {
                     return m_stringtable.add(s);
                 }
 
@@ -395,11 +399,11 @@ namespace osmium {
                 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) -> size_t {
-                        return m_primitive_block.add_string(tag.key());
+                    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) -> size_t {
-                        return m_primitive_block.add_string(tag.value());
+                    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,
@@ -417,7 +421,7 @@ namespace osmium {
                         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, object.uid());
-                        pbf_info.add_uint32(OSMFormat::Info::optional_uint32_user_sid, m_primitive_block.add_string(object.user()));
+                        pbf_info.add_uint32(OSMFormat::Info::optional_uint32_user_sid, m_primitive_block.store_in_stringtable(object.user()));
                         if (m_add_visible) {
                             pbf_info.add_bool(OSMFormat::Info::optional_bool_visible, object.visible());
                         }
@@ -450,10 +454,10 @@ namespace osmium {
                         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,   box.bottom_left().lon() * lonlat_resolution);
-                        pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_right,  box.top_right().lon()   * lonlat_resolution);
-                        pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_top,    box.top_right().lat()   * lonlat_resolution);
-                        pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_bottom, box.bottom_left().lat() * lonlat_resolution);
+                        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");
@@ -538,8 +542,8 @@ namespace osmium {
                     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) -> size_t {
-                        return m_primitive_block.add_string(member.role());
+                    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),
diff --git a/include/osmium/io/detail/read_write.hpp b/include/osmium/io/detail/read_write.hpp
index 9863bd7..773497c 100644
--- a/include/osmium/io/detail/read_write.hpp
+++ b/include/osmium/io/detail/read_write.hpp
@@ -68,6 +68,9 @@ namespace osmium {
              */
             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;
diff --git a/include/osmium/io/detail/string_table.hpp b/include/osmium/io/detail/string_table.hpp
index ae9d5f0..a048de3 100644
--- a/include/osmium/io/detail/string_table.hpp
+++ b/include/osmium/io/detail/string_table.hpp
@@ -41,6 +41,8 @@ DEALINGS IN THE SOFTWARE.
 #include <map>
 #include <string>
 
+#include <osmium/io/detail/pbf.hpp>
+
 namespace osmium {
 
     namespace io {
@@ -172,15 +174,15 @@ namespace osmium {
 
                 // These functions get you some idea how much memory was
                 // used.
-                int get_chunk_size() const noexcept {
+                size_t get_chunk_size() const noexcept {
                     return m_chunk_size;
                 }
 
-                int get_chunk_count() const noexcept {
+                size_t get_chunk_count() const noexcept {
                     return m_chunks.size();
                 }
 
-                int get_used_bytes_in_last_chunk() const noexcept {
+                size_t get_used_bytes_in_last_chunk() const noexcept {
                     return m_chunks.front().size();
                 }
 
@@ -196,9 +198,16 @@ namespace osmium {
 
             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;
-                size_t m_size;
+                uint32_t m_size;
 
             public:
 
@@ -216,18 +225,23 @@ namespace osmium {
                     m_strings.add("");
                 }
 
-                size_t size() const noexcept {
+                uint32_t size() const noexcept {
                     return m_size + 1;
                 }
 
-                size_t add(const char* s) {
+                uint32_t add(const char* s) {
                     auto f = m_index.find(s);
                     if (f != m_index.end()) {
-                        return f->second;
+                        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;
                 }
 
diff --git a/include/osmium/io/file.hpp b/include/osmium/io/file.hpp
index 3bbfacc..f5acef4 100644
--- a/include/osmium/io/file.hpp
+++ b/include/osmium/io/file.hpp
@@ -257,7 +257,7 @@ namespace osmium {
              *
              * @throws std::runtime_error
              */
-            void check() const {
+            const File& check() const {
                 if (m_file_format == file_format::unknown) {
                     std::string msg = "Could not detect file format";
                     if (!m_format_string.empty())  {
@@ -275,6 +275,7 @@ namespace osmium {
                     msg += ".";
                     throw std::runtime_error(msg);
                 }
+                return *this;
             }
 
             file_format format() const noexcept {
diff --git a/include/osmium/io/reader.hpp b/include/osmium/io/reader.hpp
index c68a8e1..e093533 100644
--- a/include/osmium/io/reader.hpp
+++ b/include/osmium/io/reader.hpp
@@ -75,6 +75,7 @@ namespace osmium {
         class Reader {
 
             osmium::io::File m_file;
+            osmium::io::detail::InputFormatFactory::create_input_type* m_input_format_creator;
             osmium::osm_entity_bits::type m_read_which_entities;
             std::atomic<bool> m_input_done;
             int m_childpid;
@@ -168,7 +169,8 @@ namespace osmium {
              *                            parsed.
              */
             explicit Reader(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities = osmium::osm_entity_bits::all) :
-                m_file(file),
+                m_file(file.check()),
+                m_input_format_creator(osmium::io::detail::InputFormatFactory::instance().get_creator_function(m_file)),
                 m_read_which_entities(read_which_entities),
                 m_input_done(false),
                 m_childpid(0),
@@ -177,7 +179,7 @@ namespace osmium {
                     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_future(std::async(std::launch::async, detail::ReadThread(m_input_queue, m_decompressor.get(), m_input_done))),
-                m_input(osmium::io::detail::InputFormatFactory::instance().create_input(m_file, m_read_which_entities, m_input_queue)) {
+                m_input((*m_input_format_creator)(m_file, m_read_which_entities, m_input_queue)) {
             }
 
             explicit Reader(const std::string& filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
diff --git a/include/osmium/io/writer.hpp b/include/osmium/io/writer.hpp
index 64afe20..018dd11 100644
--- a/include/osmium/io/writer.hpp
+++ b/include/osmium/io/writer.hpp
@@ -87,7 +87,7 @@ namespace osmium {
              * @throws std::system_error If the file could not be opened.
              */
             explicit Writer(const osmium::io::File& file, const osmium::io::Header& header = osmium::io::Header(), overwrite allow_overwrite = overwrite::no) :
-                m_file(file),
+                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_compressor(osmium::io::CompressionFactory::instance().create_compressor(file.compression(), osmium::io::detail::open_for_writing(m_file.filename(), allow_overwrite))),
diff --git a/include/osmium/osm/crc.hpp b/include/osmium/osm/crc.hpp
index eefa4a1..61ef249 100644
--- a/include/osmium/osm/crc.hpp
+++ b/include/osmium/osm/crc.hpp
@@ -46,10 +46,9 @@ DEALINGS IN THE SOFTWARE.
 
 namespace osmium {
 
-    template <class TCRC>
-    class CRC {
+    namespace util {
 
-        static inline uint16_t byte_swap_16(uint16_t value) noexcept {
+        inline uint16_t byte_swap_16(uint16_t value) noexcept {
 # if defined(__GNUC__) || defined(__clang__)
             return __builtin_bswap16(value);
 # else
@@ -57,27 +56,32 @@ namespace osmium {
 # endif
         }
 
-        static inline uint32_t byte_swap_32(uint32_t value) noexcept {
+        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 >>  8) & 0x0000FF00) |
+                   ((value <<  8) & 0x00FF0000) |
                     (value << 24);
 # endif
         }
 
-        static inline uint64_t byte_swap_64(uint64_t value) noexcept {
+        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;
+            return (val1 << 32) | val2;
 # endif
         }
 
+    }
+
+    template <class TCRC>
+    class CRC {
+
         TCRC m_crc;
 
     public:
@@ -90,37 +94,37 @@ namespace osmium {
             return m_crc;
         }
 
-        void update_bool(bool value) {
+        void update_bool(const bool value) {
             m_crc.process_byte(value);
         }
 
-        void update_int8(uint8_t value) {
+        void update_int8(const uint8_t value) {
             m_crc.process_byte(value);
         }
 
-        void update_int16(uint16_t 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 = byte_swap_16(value);
+            uint16_t v = osmium::util::byte_swap_16(value);
             m_crc.process_bytes(&v, sizeof(uint16_t));
 #endif
         }
 
-        void update_int32(uint32_t value) {
+        void update_int32(const uint32_t value) {
 #if __BYTE_ORDER == __LITTLE_ENDIAN
             m_crc.process_bytes(&value, sizeof(uint32_t));
 #else
-            uint32_t v = byte_swap_32(value);
+            uint32_t v = osmium::util::byte_swap_32(value);
             m_crc.process_bytes(&v, sizeof(uint32_t));
 #endif
         }
 
-        void update_int64(uint64_t value) {
+        void update_int64(const uint64_t value) {
 #if __BYTE_ORDER == __LITTLE_ENDIAN
             m_crc.process_bytes(&value, sizeof(uint64_t));
 #else
-            uint64_t v = byte_swap_64(value);
+            uint64_t v = osmium::util::byte_swap_64(value);
             m_crc.process_bytes(&v, sizeof(uint64_t));
 #endif
         }
diff --git a/include/osmium/osm/types.hpp b/include/osmium/osm/types.hpp
index b3414e5..c9ab423 100644
--- a/include/osmium/osm/types.hpp
+++ b/include/osmium/osm/types.hpp
@@ -57,6 +57,9 @@ namespace osmium {
      */
     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/include/osmium/util/delta.hpp b/include/osmium/util/delta.hpp
index 0c77e52..f5d6719 100644
--- a/include/osmium/util/delta.hpp
+++ b/include/osmium/util/delta.hpp
@@ -99,18 +99,18 @@ namespace osmium {
 
             TBaseIterator m_it;
             TBaseIterator m_end;
+            TTransform m_trans;
             value_type m_delta;
             DeltaEncode<value_type> m_value;
-            TTransform m_trans;
 
         public:
 
             DeltaEncodeIterator(TBaseIterator first, TBaseIterator last, TTransform& trans) :
                 m_it(first),
                 m_end(last),
-                m_delta(m_trans(m_it)),
-                m_value(m_delta),
-                m_trans(trans) {
+                m_trans(trans),
+                m_delta(m_it != m_end ? m_trans(m_it) : 0),
+                m_value(m_delta) {
             }
 
             DeltaEncodeIterator& operator++() {
diff --git a/include/osmium/util/memory_mapping.hpp b/include/osmium/util/memory_mapping.hpp
index e48aff2..4bb3641 100644
--- a/include/osmium/util/memory_mapping.hpp
+++ b/include/osmium/util/memory_mapping.hpp
@@ -43,6 +43,7 @@ DEALINGS IN THE SOFTWARE.
 #ifndef _WIN32
 # include <sys/mman.h>
 #else
+# include <fcntl.h>
 # include <io.h>
 # include <windows.h>
 # include <sys/types.h>
@@ -85,6 +86,9 @@ namespace osmium {
          * 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 {
 
@@ -655,6 +659,9 @@ inline HANDLE osmium::util::MemoryMapping::get_handle() const noexcept {
 }
 
 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);
 }
 
diff --git a/include/protozero/varint.hpp b/include/protozero/varint.hpp
index bc9c329..27536fd 100644
--- a/include/protozero/varint.hpp
+++ b/include/protozero/varint.hpp
@@ -16,10 +16,6 @@ documentation.
  * @brief Contains low-level varint and zigzag encoding and decoding functions.
  */
 
-#if __BYTE_ORDER != __LITTLE_ENDIAN
-# error "This code only works on little endian machines."
-#endif
-
 #include <cstdint>
 
 #include <protozero/exception.hpp>
diff --git a/include/protozero/version.hpp b/include/protozero/version.hpp
new file mode 100644
index 0000000..098492e
--- /dev/null
+++ b/include/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 1
+#define PROTOZERO_VERSION_PATCH 0
+
+#define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH)
+
+#define PROTOZERO_VERSION_STRING "1.1.0"
+
+
+#endif // PROTOZERO_VERSION_HPP
diff --git a/scripts/travis_script.sh b/scripts/travis_script.sh
index 75b3b36..d11ac79 100755
--- a/scripts/travis_script.sh
+++ b/scripts/travis_script.sh
@@ -19,11 +19,18 @@ if [ "${CXX}" = "g++" ]; then
     CC=gcc-4.8
 fi
 
+echo "travis_fold:start:cmake\nRunning cmake..."
 cmake -LA \
     -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
     ${WORKAROUND} \
     ..
+echo "travis_fold:end:cmake"
 
+echo "travis_fold:start:make\nRunning make..."
 make VERBOSE=1
+echo "travis_fold:end:make"
+
+echo "travis_fold:start:ctest\nRunning ctest..."
 ctest --output-on-failure
+echo "travis_fold:end:ctest"
 
diff --git a/test/data-tests/testdata-multipolygon.cpp b/test/data-tests/testdata-multipolygon.cpp
index 0fd0d98..e0d6583 100644
--- a/test/data-tests/testdata-multipolygon.cpp
+++ b/test/data-tests/testdata-multipolygon.cpp
@@ -3,6 +3,8 @@
 #include <fstream>
 #include <map>
 
+#include <gdalcpp.hpp>
+
 #include <osmium/index/map/sparse_mem_array.hpp>
 
 #include <osmium/area/assembler.hpp>
@@ -41,10 +43,9 @@ inline tagmap_type create_map(const osmium::TagList& taglist) {
 
 class TestHandler : public osmium::handler::Handler {
 
-    OGRDataSource* m_data_source;
-    OGRLayer* m_layer_point;
-    OGRLayer* m_layer_linestring;
-    OGRLayer* m_layer_polygon;
+    gdalcpp::Layer m_layer_point;
+    gdalcpp::Layer m_layer_lines;
+    gdalcpp::Layer m_layer_mpoly;
 
     osmium::geom::OGRFactory<> m_ogr_factory;
     osmium::geom::WKTFactory<> m_wkt_factory;
@@ -55,84 +56,20 @@ class TestHandler : public osmium::handler::Handler {
 
 public:
 
-    TestHandler(OGRDataSource* data_source) :
-        m_data_source(data_source),
+    TestHandler(gdalcpp::Dataset& dataset) :
+        m_layer_point(dataset, "points", wkbPoint),
+        m_layer_lines(dataset, "lines", wkbLineString),
+        m_layer_mpoly(dataset, "multipolygons", wkbMultiPolygon),
         m_out("multipolygon-tests.json") {
 
-        OGRSpatialReference sparef;
-        sparef.SetWellKnownGeogCS("WGS84");
-
-        /**************/
-
-        m_layer_point = m_data_source->CreateLayer("points", &sparef, wkbPoint, nullptr);
-        if (!m_layer_point) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_point_field_id("id", OFTReal);
-        layer_point_field_id.SetWidth(10);
-
-        if (m_layer_point->CreateField(&layer_point_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_point_field_type("type", OFTString);
-        layer_point_field_type.SetWidth(30);
-
-        if (m_layer_point->CreateField(&layer_point_field_type) != OGRERR_NONE) {
-            std::cerr << "Creating type field failed.\n";
-            exit(1);
-        }
-
-        /**************/
+        m_layer_point.add_field("id", OFTReal, 10);
+        m_layer_point.add_field("type", OFTString, 30);
 
-        m_layer_linestring = m_data_source->CreateLayer("lines", &sparef, wkbLineString, nullptr);
-        if (!m_layer_linestring) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
+        m_layer_lines.add_field("id", OFTReal, 10);
+        m_layer_lines.add_field("type", OFTString, 30);
 
-        OGRFieldDefn layer_linestring_field_id("id", OFTReal);
-        layer_linestring_field_id.SetWidth(10);
-
-        if (m_layer_linestring->CreateField(&layer_linestring_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_linestring_field_type("type", OFTString);
-        layer_linestring_field_type.SetWidth(30);
-
-        if (m_layer_linestring->CreateField(&layer_linestring_field_type) != OGRERR_NONE) {
-            std::cerr << "Creating type field failed.\n";
-            exit(1);
-        }
-
-        /**************/
-
-        m_layer_polygon = m_data_source->CreateLayer("multipolygons", &sparef, wkbMultiPolygon, nullptr);
-        if (!m_layer_polygon) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_polygon_field_id("id", OFTInteger);
-        layer_polygon_field_id.SetWidth(10);
-
-        if (m_layer_polygon->CreateField(&layer_polygon_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_polygon_field_from_type("from_type", OFTString);
-        layer_polygon_field_from_type.SetWidth(1);
-
-        if (m_layer_polygon->CreateField(&layer_polygon_field_from_type) != OGRERR_NONE) {
-            std::cerr << "Creating from_type field failed.\n";
-            exit(1);
-        }
+        m_layer_mpoly.add_field("id", OFTReal, 10);
+        m_layer_mpoly.add_field("from_type", OFTString, 1);
     }
 
     ~TestHandler() {
@@ -140,34 +77,18 @@ public:
     }
 
     void node(const osmium::Node& node) {
-        OGRFeature* feature = OGRFeature::CreateFeature(m_layer_point->GetLayerDefn());
-        std::unique_ptr<OGRPoint> ogr_point = m_ogr_factory.create_point(node);
-        feature->SetGeometry(ogr_point.get());
-        feature->SetField("id", static_cast<double>(node.id()));
-        feature->SetField("type", node.tags().get_value_by_key("type"));
-
-        if (m_layer_point->CreateFeature(feature) != OGRERR_NONE) {
-            std::cerr << "Failed to create feature.\n";
-            exit(1);
-        }
-
-        OGRFeature::DestroyFeature(feature);
+        gdalcpp::Feature feature(m_layer_point, m_ogr_factory.create_point(node));
+        feature.set_field("id", static_cast<double>(node.id()));
+        feature.set_field("type", node.tags().get_value_by_key("type"));
+        feature.add_to_layer();
     }
 
     void way(const osmium::Way& way) {
         try {
-            std::unique_ptr<OGRLineString> ogr_linestring = m_ogr_factory.create_linestring(way);
-            OGRFeature* feature = OGRFeature::CreateFeature(m_layer_linestring->GetLayerDefn());
-            feature->SetGeometry(ogr_linestring.get());
-            feature->SetField("id", static_cast<double>(way.id()));
-            feature->SetField("type", way.tags().get_value_by_key("type"));
-
-            if (m_layer_linestring->CreateFeature(feature) != OGRERR_NONE) {
-                std::cerr << "Failed to create feature.\n";
-                exit(1);
-            }
-
-            OGRFeature::DestroyFeature(feature);
+            gdalcpp::Feature feature(m_layer_lines, m_ogr_factory.create_linestring(way));
+            feature.set_field("id", static_cast<double>(way.id()));
+            feature.set_field("type", way.tags().get_value_by_key("type"));
+            feature.add_to_layer();
         } catch (osmium::geometry_error&) {
             std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
         }
@@ -200,10 +121,8 @@ public:
             m_out << "INVALID\"\n}";
         }
         try {
-            std::unique_ptr<OGRMultiPolygon> ogr_polygon = m_ogr_factory.create_multipolygon(area);
-            OGRFeature* feature = OGRFeature::CreateFeature(m_layer_polygon->GetLayerDefn());
-            feature->SetGeometry(ogr_polygon.get());
-            feature->SetField("id", static_cast<int>(area.orig_id()));
+            gdalcpp::Feature feature(m_layer_mpoly, m_ogr_factory.create_multipolygon(area));
+            feature.set_field("id", static_cast<double>(area.orig_id()));
 
             std::string from_type;
             if (area.from_way()) {
@@ -211,14 +130,8 @@ public:
             } else {
                 from_type = "r";
             }
-            feature->SetField("from_type", from_type.c_str());
-
-            if (m_layer_polygon->CreateFeature(feature) != OGRERR_NONE) {
-                std::cerr << "Failed to create feature.\n";
-                exit(1);
-            }
-
-            OGRFeature::DestroyFeature(feature);
+            feature.set_field("from_type", from_type.c_str());
+            feature.add_to_layer();
         } catch (osmium::geometry_error&) {
             std::cerr << "Ignoring illegal geometry for area " << area.id() << " created from " << (area.from_way() ? "way" : "relation") << " with id=" << area.orig_id() << ".\n";
         }
@@ -228,26 +141,6 @@ public:
 
 /* ================================================== */
 
-OGRDataSource* initialize_database(const std::string& output_format, const std::string& output_filename) {
-    OGRRegisterAll();
-
-    OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(output_format.c_str());
-    if (!driver) {
-        std::cerr << output_format << " driver not available.\n";
-        exit(1);
-    }
-
-    CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
-    const char* options[] = { "SPATIALITE=TRUE", nullptr };
-    OGRDataSource* data_source = driver->CreateDataSource(output_filename.c_str(), const_cast<char**>(options));
-    if (!data_source) {
-        std::cerr << "Creation of output file failed.\n";
-        exit(1);
-    }
-
-    return data_source;
-}
-
 int main(int argc, char* argv[]) {
     if (argc != 2) {
         std::cerr << "Usage: " << argv[0] << " INFILE\n";
@@ -258,9 +151,10 @@ int main(int argc, char* argv[]) {
     std::string input_filename(argv[1]);
     std::string output_filename("multipolygon.db");
 
-    OGRDataSource* data_source = initialize_database(output_format, output_filename);
+    CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
+    gdalcpp::Dataset dataset(output_format, output_filename, "", { "SPATIALITE=TRUE" });
 
-    osmium::area::ProblemReporterOGR problem_reporter(data_source);
+    osmium::area::ProblemReporterOGR problem_reporter(dataset);
     osmium::area::Assembler::config_type assembler_config(&problem_reporter);
     assembler_config.enable_debug_output();
     osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config);
@@ -275,7 +169,7 @@ int main(int argc, char* argv[]) {
     location_handler_type location_handler(index);
     location_handler.ignore_errors();
 
-    TestHandler test_handler(data_source);
+    TestHandler test_handler(dataset);
 
     std::cerr << "Pass 2...\n";
     osmium::io::Reader reader2(input_filename);
@@ -284,8 +178,5 @@ int main(int argc, char* argv[]) {
     }));
     reader2.close();
     std::cerr << "Pass 2 done\n";
-
-    OGRDataSource::DestroyDataSource(data_source);
-    OGRCleanupAll();
 }
 
diff --git a/test/data-tests/testdata-overview.cpp b/test/data-tests/testdata-overview.cpp
index 2d63dc6..2c88ece 100644
--- a/test/data-tests/testdata-overview.cpp
+++ b/test/data-tests/testdata-overview.cpp
@@ -2,6 +2,8 @@
 
 #include <iostream>
 
+#include <gdalcpp.hpp>
+
 #include <osmium/index/map/sparse_mem_array.hpp>
 
 #include <osmium/geom/ogr.hpp>
@@ -15,154 +17,53 @@ typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type;
 
 class TestOverviewHandler : public osmium::handler::Handler {
 
-    OGRDataSource* m_data_source;
-
-    OGRLayer* m_layer_nodes;
-    OGRLayer* m_layer_labels;
-    OGRLayer* m_layer_ways;
+    gdalcpp::Layer m_layer_nodes;
+    gdalcpp::Layer m_layer_labels;
+    gdalcpp::Layer m_layer_ways;
 
     osmium::geom::OGRFactory<> m_factory;
 
 public:
 
-    TestOverviewHandler(const std::string& driver_name, const std::string& filename) {
-
-        OGRRegisterAll();
-
-        OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str());
-        if (!driver) {
-            std::cerr << driver_name << " driver not available.\n";
-            exit(1);
-        }
-
-        CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
-        const char* options[] = { "SPATIALITE=TRUE", nullptr };
-        m_data_source = driver->CreateDataSource(filename.c_str(), const_cast<char**>(options));
-        if (!m_data_source) {
-            std::cerr << "Creation of output file failed.\n";
-            exit(1);
-        }
-
-        OGRSpatialReference sparef;
-        sparef.SetWellKnownGeogCS("WGS84");
+    TestOverviewHandler(gdalcpp::Dataset& dataset) :
+        m_layer_nodes(dataset, "nodes", wkbPoint),
+        m_layer_labels(dataset, "labels", wkbPoint),
+        m_layer_ways(dataset, "ways", wkbLineString) {
 
-        // nodes layer
-
-        m_layer_nodes = m_data_source->CreateLayer("nodes", &sparef, wkbPoint, nullptr);
-        if (!m_layer_nodes) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_nodes_field_id("id", OFTReal);
-        layer_nodes_field_id.SetWidth(10);
-
-        if (m_layer_nodes->CreateField(&layer_nodes_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
-
-        // labels layer
-
-        m_layer_labels = m_data_source->CreateLayer("labels", &sparef, wkbPoint, nullptr);
-        if (!m_layer_labels) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_labels_field_id("id", OFTReal);
-        layer_labels_field_id.SetWidth(10);
-
-        if (m_layer_labels->CreateField(&layer_labels_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
+        m_layer_nodes.add_field("id", OFTReal, 10);
 
-        OGRFieldDefn layer_labels_field_label("label", OFTString);
-        layer_labels_field_label.SetWidth(30);
+        m_layer_labels.add_field("id", OFTReal, 10);
+        m_layer_labels.add_field("label", OFTString, 30);
 
-        if (m_layer_labels->CreateField(&layer_labels_field_label) != OGRERR_NONE) {
-            std::cerr << "Creating label field failed.\n";
-            exit(1);
-        }
-
-        // ways layer
-
-        m_layer_ways = m_data_source->CreateLayer("ways", &sparef, wkbLineString, nullptr);
-        if (!m_layer_ways) {
-            std::cerr << "Layer creation failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_way_field_id("id", OFTReal);
-        layer_way_field_id.SetWidth(10);
-
-        if (m_layer_ways->CreateField(&layer_way_field_id) != OGRERR_NONE) {
-            std::cerr << "Creating id field failed.\n";
-            exit(1);
-        }
-
-        OGRFieldDefn layer_way_field_test("test", OFTInteger);
-        layer_way_field_test.SetWidth(3);
-
-        if (m_layer_ways->CreateField(&layer_way_field_test) != OGRERR_NONE) {
-            std::cerr << "Creating test field failed.\n";
-            exit(1);
-        }
-    }
-
-    ~TestOverviewHandler() {
-        OGRDataSource::DestroyDataSource(m_data_source);
-        OGRCleanupAll();
+        m_layer_ways.add_field("id", OFTReal, 10);
+        m_layer_ways.add_field("test", OFTInteger, 3);
     }
 
     void node(const osmium::Node& node) {
         const char* label = node.tags().get_value_by_key("label");
         if (label) {
-            OGRFeature* feature = OGRFeature::CreateFeature(m_layer_labels->GetLayerDefn());
-            std::unique_ptr<OGRPoint> ogr_point = m_factory.create_point(node);
-            feature->SetGeometry(ogr_point.get());
-            feature->SetField("id", static_cast<double>(node.id()));
-            feature->SetField("label", label);
-
-            if (m_layer_labels->CreateFeature(feature) != OGRERR_NONE) {
-                std::cerr << "Failed to create feature.\n";
-                exit(1);
-            }
-
-            OGRFeature::DestroyFeature(feature);
+            gdalcpp::Feature feature(m_layer_labels, m_factory.create_point(node));
+            feature.set_field("id", static_cast<double>(node.id()));
+            feature.set_field("label", label);
+            feature.add_to_layer();
         } else {
-            OGRFeature* feature = OGRFeature::CreateFeature(m_layer_nodes->GetLayerDefn());
-            std::unique_ptr<OGRPoint> ogr_point = m_factory.create_point(node);
-            feature->SetGeometry(ogr_point.get());
-            feature->SetField("id", static_cast<double>(node.id()));
-
-            if (m_layer_nodes->CreateFeature(feature) != OGRERR_NONE) {
-                std::cerr << "Failed to create feature.\n";
-                exit(1);
-            }
-            OGRFeature::DestroyFeature(feature);
+            gdalcpp::Feature feature(m_layer_nodes, m_factory.create_point(node));
+            feature.set_field("id", static_cast<double>(node.id()));
+            feature.add_to_layer();
         }
     }
 
     void way(const osmium::Way& way) {
         try {
-            std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way);
-            OGRFeature* feature = OGRFeature::CreateFeature(m_layer_ways->GetLayerDefn());
-            feature->SetGeometry(ogr_linestring.get());
-            feature->SetField("id", static_cast<double>(way.id()));
+            gdalcpp::Feature feature(m_layer_ways, m_factory.create_linestring(way));
+            feature.set_field("id", static_cast<double>(way.id()));
 
             const char* test = way.tags().get_value_by_key("test");
             if (test) {
-                feature->SetField("test", test);
-            }
-
-            if (m_layer_ways->CreateFeature(feature) != OGRERR_NONE) {
-                std::cerr << "Failed to create feature.\n";
-                exit(1);
+                feature.set_field("test", test);
             }
 
-            OGRFeature::DestroyFeature(feature);
+            feature.add_to_layer();
         } catch (osmium::geometry_error&) {
             std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
         }
@@ -183,13 +84,16 @@ int main(int argc, char* argv[]) {
     std::string output_filename("testdata-overview.db");
     ::unlink(output_filename.c_str());
 
+    CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
+    gdalcpp::Dataset dataset(output_format, output_filename, "", { "SPATIALITE=TRUE" });
+
     osmium::io::Reader reader(input_filename);
 
     index_type index;
     location_handler_type location_handler(index);
     location_handler.ignore_errors();
 
-    TestOverviewHandler handler(output_format, output_filename);
+    TestOverviewHandler handler(dataset);
 
     osmium::apply(reader, location_handler, handler);
     reader.close();
diff --git a/test/t/basic/test_crc.cpp b/test/t/basic/test_crc.cpp
index aab1013..fcd50a1 100644
--- a/test/t/basic/test_crc.cpp
+++ b/test/t/basic/test_crc.cpp
@@ -24,6 +24,27 @@ TEST_CASE("CRC of basic datatypes") {
         REQUIRE(crc32().checksum() == 0x8fe62899);
     }
 
+    SECTION("Int16") {
+        crc32.update_int16(0x0123U);
+        crc32.update_int16(0x1234U);
+
+        REQUIRE(crc32().checksum() == 0xda923744);
+    }
+
+    SECTION("Int32") {
+        crc32.update_int32(0x01234567UL);
+        crc32.update_int32(0x12345678UL);
+
+        REQUIRE(crc32().checksum() == 0x9b4e2af3);
+    }
+
+    SECTION("Int64") {
+        crc32.update_int64(0x0123456789abcdefULL);
+        crc32.update_int64(0x123456789abcdef0ULL);
+
+        REQUIRE(crc32().checksum() == 0x6d8b7267);
+    }
+
     SECTION("String") {
         const char* str = "foobar";
         crc32.update_string(str);
diff --git a/test/t/basic/test_relation.cpp b/test/t/basic/test_relation.cpp
index fd5c7b4..4b608ff 100644
--- a/test/t/basic/test_relation.cpp
+++ b/test/t/basic/test_relation.cpp
@@ -63,3 +63,14 @@ TEST_CASE("Build relation") {
     crc32.update(relation);
     REQUIRE(crc32().checksum() == 0xebcd836d);
 }
+
+TEST_CASE("Member role too long") {
+    osmium::memory::Buffer buffer(10000);
+
+    osmium::builder::RelationMemberListBuilder builder(buffer);
+
+    const char role[2000] = "";
+    builder.add_member(osmium::item_type::node, 1, role, 1024);
+    REQUIRE_THROWS(builder.add_member(osmium::item_type::node, 1, role, 1025));
+}
+
diff --git a/test/t/tags/test_tag_list.cpp b/test/t/tags/test_tag_list.cpp
index 77523e7..295f51a 100644
--- a/test/t/tags/test_tag_list.cpp
+++ b/test/t/tags/test_tag_list.cpp
@@ -100,3 +100,14 @@ TEST_CASE("empty keys and values are okay") {
     REQUIRE(std::string("") == tl.get_value_by_key("empty value"));
     REQUIRE(std::string("empty key") == tl.get_value_by_key(""));
 }
+
+TEST_CASE("tag key or value is too long") {
+    osmium::memory::Buffer buffer(10240);
+    osmium::builder::TagListBuilder builder(buffer);
+
+    const char kv[2000] = "";
+    builder.add_tag(kv, 1, kv, 1000);
+    REQUIRE_THROWS(builder.add_tag(kv, 1500, kv, 1));
+    REQUIRE_THROWS(builder.add_tag(kv, 1, kv, 1500));
+}
+

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



More information about the Pkg-grass-devel mailing list