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 <sebas...@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 <joc...@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 _______________________________________________ Pkg-grass-devel mailing list Pkg-grass-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel