pax_global_header00006660000000000000000000000064131500422340014504gustar00rootroot0000000000000052 comment=e9e8cd5f023cd4cc46db26adf1c78b54aa110511 osmium-tool-1.7.1/000077500000000000000000000000001315004223400137765ustar00rootroot00000000000000osmium-tool-1.7.1/.gitattributes000066400000000000000000000001031315004223400166630ustar00rootroot00000000000000*.osm -crlf *.osc -crlf *.opl -crlf *.osh -crlf *-result.txt -crlf osmium-tool-1.7.1/.gitignore000066400000000000000000000000621315004223400157640ustar00rootroot00000000000000.*.swp .ycm_extra_conf.pyc /build /libosmium-deps osmium-tool-1.7.1/.travis.yml000066400000000000000000000135001315004223400161060ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # Configuration for continuous integration service at travis-ci.org # #----------------------------------------------------------------------------- language: generic sudo: false # http://docs.travis-ci.com/user/apt/ addons: apt: sources: - boost-latest - ubuntu-toolchain-r-test packages: - g++-4.8 - gcc-4.8 - libboost1.55-dev - libboost-program-options1.55-dev - pandoc #----------------------------------------------------------------------------- matrix: include: # 1/ Linux Clang Builds - os: linux compiler: linux-clang35-release addons: apt: sources: ['llvm-toolchain-precise-3.5', 'ubuntu-toolchain-r-test', 'boost-latest'] packages: ['clang-3.5', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='clang++-3.5' BUILD_TYPE='Release' - os: linux compiler: linux-clang35-dev addons: apt: sources: ['llvm-toolchain-precise-3.5', 'ubuntu-toolchain-r-test', 'boost-latest'] packages: ['clang-3.5', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='clang++-3.5' BUILD_TYPE='Dev' - os: linux compiler: linux-clang37-release addons: apt: sources: ['llvm-toolchain-precise-3.7', 'ubuntu-toolchain-r-test', 'boost-latest'] packages: ['clang-3.7', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='clang++-3.7' BUILD_TYPE='Release' - os: linux compiler: linux-clang37-dev addons: apt: sources: ['llvm-toolchain-precise-3.7', 'ubuntu-toolchain-r-test', 'boost-latest'] packages: ['clang-3.7', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='clang++-3.7' BUILD_TYPE='Dev' - os: linux compiler: linux-clang38-release addons: apt: sources: ['llvm-toolchain-precise-3.8', 'ubuntu-toolchain-r-test', 'boost-latest'] packages: ['clang-3.8', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='clang++-3.8' BUILD_TYPE='Release' - os: linux compiler: linux-clang38-dev addons: apt: sources: ['llvm-toolchain-precise-3.8', 'ubuntu-toolchain-r-test', 'boost-latest'] packages: ['clang-3.8', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='clang++-3.8' BUILD_TYPE='Dev' # 2/ Linux GCC Builds - os: linux compiler: linux-gcc48-release addons: apt: sources: ['ubuntu-toolchain-r-test', 'boost-latest'] packages: ['g++-4.8', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='g++-4.8' COMPILER_FLAGS='-Wno-return-type' BUILD_TYPE='Release' - os: linux compiler: linux-gcc48-dev addons: apt: sources: ['ubuntu-toolchain-r-test', 'boost-latest'] packages: ['g++-4.8', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='g++-4.8' COMPILER_FLAGS='-Wno-return-type' BUILD_TYPE='Dev' - os: linux compiler: linux-gcc49-release addons: apt: sources: ['ubuntu-toolchain-r-test', 'boost-latest'] packages: ['g++-4.9', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='g++-4.9' BUILD_TYPE='Release' - os: linux compiler: linux-gcc49-dev addons: apt: sources: ['ubuntu-toolchain-r-test', 'boost-latest'] packages: ['g++-4.9', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='g++-4.9' BUILD_TYPE='Dev' - os: linux compiler: linux-gcc5-release addons: apt: sources: ['ubuntu-toolchain-r-test', 'boost-latest'] packages: ['g++-5', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='g++-5' BUILD_TYPE='Release' - os: linux compiler: linux-gcc5-dev addons: apt: sources: ['ubuntu-toolchain-r-test', 'boost-latest'] packages: ['g++-5', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='g++-5' BUILD_TYPE='Dev' - os: linux compiler: linux-gcc6-release addons: apt: sources: ['ubuntu-toolchain-r-test', 'boost-latest'] packages: ['g++-6', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='g++-6' BUILD_TYPE='Release' - os: linux compiler: linux-gcc6-dev addons: apt: sources: ['ubuntu-toolchain-r-test', 'boost-latest'] packages: ['g++-6', 'libboost1.55-all-dev', 'pandoc'] env: COMPILER='g++-6' BUILD_TYPE='Dev' # 3/ OSX Clang Builds - os: osx osx_image: xcode6.4 compiler: xcode64-clang-release env: COMPILER='clang++' BUILD_TYPE='Release' - os: osx osx_image: xcode6.4 compiler: xcode64-clang-dev env: COMPILER='clang++' BUILD_TYPE='Dev' - os: osx osx_image: xcode7 compiler: xcode7-clang-release env: COMPILER='clang++' BUILD_TYPE='Release' - os: osx osx_image: xcode7 compiler: xcode7-clang-dev env: COMPILER='clang++' BUILD_TYPE='Dev' - os: osx osx_image: xcode8 compiler: xcode8-clang-release env: COMPILER='clang++' BUILD_TYPE='Release' - os: osx osx_image: xcode8 compiler: xcode8-clang-dev env: COMPILER='clang++' BUILD_TYPE='Dev' #----------------------------------------------------------------------------- install: - git clone --quiet --depth 1 https://github.com/osmcode/libosmium.git ../libosmium - | if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then brew install cmake boost || true fi - cmake --version before_script: - cd ${TRAVIS_BUILD_DIR} - mkdir build && cd build - CXX=${COMPILER} CXXFLAGS=${COMPILER_FLAGS} cmake -LA .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} script: - make VERBOSE=1 && ctest --output-on-failure #----------------------------------------------------------------------------- osmium-tool-1.7.1/.ycm_extra_conf.py000066400000000000000000000023031315004223400174240ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # Configuration for YouCompleteMe Vim plugin # # http://valloric.github.io/YouCompleteMe/ # #----------------------------------------------------------------------------- from os.path import realpath, dirname basedir = dirname(realpath(__file__)) # some default flags # for more information install clang-3.2-doc package and # check UsersManual.html flags = [ '-Werror', '-Wall', '-Wextra', '-pedantic', '-Wno-return-type', '-Wno-unused-parameter', '-Wno-unused-variable', '-std=c++11', # '-x' and 'c++' also required # use 'c' for C projects '-x', 'c++', # workaround for https://github.com/Valloric/YouCompleteMe/issues/303 # also see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=800618 '-isystem', '/usr/lib/ycmd/clang_includes/', '-I%s/include' % basedir, '-I%s/test/include' % basedir, '-I%s/src' % basedir, # libosmium include dirs '-I%s/../libosmium/include' % basedir, ] # youcompleteme is calling this function to get flags # You can also set database for flags. Check: JSONCompilationDatabase.html in # clang-3.2-doc package def FlagsForFile( filename ): return { 'flags': flags, 'do_cache': True } osmium-tool-1.7.1/CHANGELOG.md000066400000000000000000000300141315004223400156050ustar00rootroot00000000000000 # Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] - ### Added ### Changed ### Fixed ## [1.7.1] - 2017-08-25 ### Added - Extended some man pages. ### Changed - Allow any OSM file header option with `fileinfo -g`. There is no final list of possible options, so any option should be allowed. - Needs libosmium 2.13.1. ### Fixed - Specifying extracts in config files was broken. The `extract` command was not reading config files correctly and all resulting OSM files were empty. Specifying an extract on the command line using `--bbox` or `--polygon` was still working. - Allow zero-length index files in renumber. ## [1.7.0] - 2017-08-15 ### Added - New `export` command for exporting OSM data into GeoJSON format. The OSM data model with its nodes, ways, and relations is very different from the data model usually used for geodata with features having point, linestring, or polygon geometries. The export command transforms OSM data into a more usual GIS data model. Nodes will be translated into points and ways into linestrings or polygons (if they are closed ways). Multipolygon and boundary relations will be translated into multipolygons. This transformation is not loss-less, especially information in non-multipolygon, non-boundary relations is lost. All tags are preserved in this process. Note that most GIS formats (such as Shapefiles, etc.) do not support arbitrary tags. Transformation into other GIS formats will need extra steps mapping tags to a limited list of attributes. This is outside the scope of this command. - New `--bbox/-B` option to `changeset-filter` command. Only changesets with bounding boxes overlapping this bounding box are copied to the output. - Support for the new `flex_mem` index type for node location indexes. It is used by default in the `add_locations_to_ways` and `export` commands. The new man page `osmium-index-types` documents this and other available indexes. ### Changed - The order of objects in an OSM file expected by some commands as well as the order created by the `sort` command has changed when negative IDs are involved. (Negative IDs are sometimes used for objects that have not yet been uploaded to the OSM server.) The negative IDs are ordered now before the positive ones, both in order of their absolute value. This is the same ordering as JOSM uses. - The commands `check-refs`, `fileinfo`, and `renumber` now also work with negative object IDs. - Allow leading spaces in ID files for `getid` command. - Various error messages and man pages have been clarified. - Updated minimum libosmium version required to 2.13.0. - Update version of Catch unit test framework to 1.9.7. ### Fixed - Libosmium fix: Changesets with more than 2^16 characters in comments now work. - Libosmium fix: Changeset bounding boxes are now always output to OSM files (any format) if at least one of the corners is defined. This is needed to handle broken data from the main OSM database which contains such cases. This now also works when reading OPL files. ## [1.6.1] - 2017-04-10 ### Changed - Clarify differences between `diff` and `derive-changes` commands in man pages. - Needs current libosmium 2.12.1 now. ### Fixed - Use empty header for apply-changes instead of the one from input file. - Call 'less' with -R when using ANSI colors with 'show' command. - Do not show progress options on show command. ## [1.6.0] - 2017-03-07 ### Added - New `tags-filter` command for filtering OSM files based on tag keys and values. - Add option `--locations-on-ways` to `apply-changes` for updating files created with `add-locations-to-ways`. - Add optional `output_header` on extracts in config file. (#47) - Add `--change-file-format` to `apply-changes` format for setting format of change files. - Add `--set-bounds` option to `extract` command. ### Changed - Now requires libosmium 2.12. - Deprecated `--history` option on `getid` command in favour of `--with-history` for consistency with other commands. - Use new `RelationsMapIndex` from libosmium for `getid` instead of `std::multimap`. - Update included version of Catch unit test framework to 1.8.1 which required some changes in the tests. - Use `osmium::util::file_size` instead of our own `filesize()` function. - Miscellaneous code cleanups and improved warning messages and man pages. ### Fixed - Add `-pthread` compiler and linker options on Linux/OSX. This should fix a problem where some linker versions will not link binaries correctly when the `--as-needed` option is used. - Typo in GeoJSON parser which broke MultiPolygon support. - Wrong description of -S option in extract man page. - Windows build problem related to forced build for old Windows versions. - All but the first polygon in a GeoJSON multipolygon were ignored by the `extract` command. - Zsh command line completion for some commands. ## [1.5.1] - 2017-01-19 ### Changed - Build with warnings in all build types, not only "Dev". - Better error messages for command line errors. ### Fixed - Make `--overwrite` and `--fsync` work in `derive_changes` command. - A dereference of end iterator in `derive_changes`. - You can not specify the special file name "-" (to read from STDIN) several times for commands reading multiple files. ## [1.5.0] - 2017-01-18 ### Added - New `extract` command to cut out geographical regions from an OSM file using a bounding box or (multi)polygon. ## [1.4.1] - 2016-11-20 ### Added - Add hint to error message about `--overwrite` option when trying to open an existing file. - Check the required libosmium version in CMake build. ### Changed - Add --ignore-missing-nodes to `add-locations-to-ways` subcommand. If this is not set, the command will now fail if there are missing nodes needed for ways. - The `check-refs` and `getid` subcommands now use the IdSet class from the newest libosmium making them more efficient (especially on very large input files). - Improved error messages for low-level errors. - Now requires at least libosmium 2.10.2 and protozero 1.4.5. ### Fixed - Consistently handle `--output-header` option in all commands that create standard OSM files. - Handling of some output options was not correct in `diff` command. They do now what is documented and it is documented what they do. - Progress bar and output from verbose mode will now be kept separate. ## [1.4.0] - 2016-09-15 ### Added - The new manual is a more gentle introduction into the capabilities of Osmium Tool. Numerous man page additions. - New `merge` command to merge any number of sorted OSM files. - New `derive-changes` command to create change file from two OSM data files. - New `diff` command to show differences between OSM files. - The `renumber` command can now optionally only renumber some object types. - Version information is now printed including the git commit id and always shown in verbose mode. - Added `iwyu` target to CMake config. - Progress bars will be shown on some commands. (This is configurable at run time with the `--progress` and `--no-progress` options.) ### Changed - The `apply-changes` subcommand now detects whether it is updating a normal OSM file or an OSM history file based on file name suffix (can be forced with `--with-history`). The options `--simplify` and `--remove-deleted` are now deprecated (a warning will be written to stderr). For normal OSM files, output is always simplified and deleted objects are removed, for OSM history files, all versions of all objects are kept. - Also check ordering of changesets in `osmium fileinfo -e`. - The `getid` options `-i` and `-I` can now be used multiple times. - More consistent warning messages. - Compiles much faster due to include optimizations. - Update the included RapidJSON to version 1.1.0. ### Fixed - CMake now creates `compile_commands.json`. - Wrapper script now works with quoted arguments. ## [1.3.1] - 2016-06-08 ### Added - Check that input files are correctly ordered in the `renumber` and `check-refs` commands. - Most commands now show the memory used in verbose mode. - New option `-h`/`--help` on most commands shows command line options. - New `--default-type` option to getid command. - The `getid` command can now recursively add all referenced objects. - New `show` command to quickly see OSM file contents. - New `add-locations-to-ways` command. ### Changed - Much faster and more memory efficient implementation of the `renumber` command. - The `getid` command can now read IDs from *stdin*. - Also show libosmium version when running `version` subcommand. ## [1.3.0] - 2015-11-17 ### Added - Add new `sort` subcommand for sorting OSM data files, history files, and change files. - Add new `changeset-filter` subcommand. - New option `--fsync` on all subcommands that write an OSM file. Will call fsync after writing any file. ### Changed - Uses new libosmium version now (use at least libosmium version 2.5.3). ## [1.2.1] - 2015-08-31 ### Changed - Uses new libosmium version now (use at least libosmium version 2.4.1). ### Fixed - Several Windows line ending issues were fixed. Consistently uses files in binary mode now with LF line endings. - CRC calculation fixed in libosmium. ## [1.2.0] - 2015-08-18 ### Added - Added lots of tests. ### Changed - Uses new libosmium version now (use at least libosmium version 2.3.0). - Many corrections and updates in manual pages. - Change CRC32 implementation. The new implementation uses the newly added CRC functions from libosmium. This should make the CRC independent of host architecture and endianness. - Lots of refactoring code cleanups. ### Fixed - Remove license that's not applicable from LICENSE-rapidjson.txt. - Renumbering didn't work properly in some cases. - Fix error checking in renumber command. ## [1.1.1] - 2015-07-04 ### Fixed - Osmium fileinfo --show-variables didn't work properly. - Improved zsh autocompletion ## [1.1.0] - 2015-07-04 ### Added - New getid subcommand to filter by node/way/relation IDs. - New renumber subcommand to renumber IDs in OSM files. - New check-refs subcommand to check referential integrity in OSM files. - Improved testing framework and added some functional tests. - Fileinfo subcommand can now output a single variable using `-g`. - Fileinfo subcommand can now output all data in JSON format using the RapidJSON library (which is included in the code). - Fileinfo subcommand now also shows largest ID of each type. ### Changed - Lots of refactoring to handle command line parsing for different subcommands in a uniform manner. Now pretty much all command line options concerning file input and output are consistent across subcommand. - Uses newest libosmium. ### Fixed - Time-fiter subcommand: Fixed case where objects are updated twice in the same second. - Some corrections in man pages. ## [1.0.1] - 2015-03-31 ### Changed - Minor updates to documentation and build system [unreleased]: https://github.com/osmcode/osmium-tool/compare/v1.7.1...HEAD [1.7.1]: https://github.com/osmcode/osmium-tool/compare/v1.7.0...v1.7.1 [1.7.0]: https://github.com/osmcode/osmium-tool/compare/v1.6.1...v1.7.0 [1.6.1]: https://github.com/osmcode/osmium-tool/compare/v1.6.0...v1.6.1 [1.6.0]: https://github.com/osmcode/osmium-tool/compare/v1.5.1...v1.6.0 [1.5.1]: https://github.com/osmcode/osmium-tool/compare/v1.5.0...v1.5.1 [1.5.0]: https://github.com/osmcode/osmium-tool/compare/v1.4.1...v1.5.0 [1.4.1]: https://github.com/osmcode/osmium-tool/compare/v1.4.0...v1.4.1 [1.4.0]: https://github.com/osmcode/osmium-tool/compare/v1.3.1...v1.4.0 [1.3.1]: https://github.com/osmcode/osmium-tool/compare/v1.3.0...v1.3.1 [1.3.0]: https://github.com/osmcode/osmium-tool/compare/v1.2.1...v1.3.0 [1.2.1]: https://github.com/osmcode/osmium-tool/compare/v1.2.0...v1.2.1 [1.2.0]: https://github.com/osmcode/osmium-tool/compare/v1.1.0...v1.2.0 [1.1.1]: https://github.com/osmcode/osmium-tool/compare/v1.1.0...v1.1.1 [1.1.0]: https://github.com/osmcode/osmium-tool/compare/v1.0.1...v1.1.0 [1.0.1]: https://github.com/osmcode/osmium-tool/compare/v1.0.0...v1.0.1 osmium-tool-1.7.1/CMakeLists.txt000066400000000000000000000143571315004223400165500ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool # #----------------------------------------------------------------------------- cmake_minimum_required(VERSION 2.8 FATAL_ERROR) list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") #----------------------------------------------------------------------------- # # Project version # #----------------------------------------------------------------------------- # It is important that this setting remains before the "project" call. set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev" CACHE STRING "List of available configuration types" FORCE) project(osmium) set(OSMIUM_VERSION_MAJOR 1) set(OSMIUM_VERSION_MINOR 7) set(OSMIUM_VERSION_PATCH 1) set(OSMIUM_VERSION ${OSMIUM_VERSION_MAJOR}.${OSMIUM_VERSION_MINOR}.${OSMIUM_VERSION_PATCH}) set(AUTHOR "Jochen Topf ") set(CMAKE_EXPORT_COMPILE_COMMANDS ON) #----------------------------------------------------------------------------- # # Find external dependencies # #----------------------------------------------------------------------------- find_package(Boost 1.55.0 REQUIRED COMPONENTS program_options) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) find_package(Osmium 2.13.1 REQUIRED COMPONENTS io) include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS}) #----------------------------------------------------------------------------- # # Optional "cppcheck" target that checks C++ code # #----------------------------------------------------------------------------- message(STATUS "Looking for cppcheck") find_program(CPPCHECK cppcheck) if(CPPCHECK) message(STATUS "Looking for cppcheck - found") set(CPPCHECK_OPTIONS --enable=warning,style,performance,portability,information,missingInclude) # cpp doesn't find system includes for some reason, suppress that report set(CPPCHECK_OPTIONS ${CPPCHECK_OPTIONS} --suppress=missingIncludeSystem) add_custom_target(cppcheck ${CPPCHECK} --std=c++11 ${CPPCHECK_OPTIONS} ${CMAKE_SOURCE_DIR}/src/*pp) else() message(STATUS "Looking for cppcheck - not found") message(STATUS " Build target 'cppcheck' will not be available") endif() #----------------------------------------------------------------------------- # # Optional "iwyu" target to check headers # http://include-what-you-use.org/ # #----------------------------------------------------------------------------- find_program(IWYU_TOOL NAMES iwyu_tool iwyu_tool.py) if(IWYU_TOOL) message(STATUS "Looking for iwyu_tool.py - found") add_custom_target(iwyu ${IWYU_TOOL} -p ${CMAKE_BINARY_DIR} -- --mapping_file=${CMAKE_SOURCE_DIR}/iwyu.imp) else() message(STATUS "Looking for iwyu_tool.py - not found") message(STATUS " Make target 'iwyu' will not be available") endif() #----------------------------------------------------------------------------- # # Decide which C++ version to use (Minimum/default: C++11). # #----------------------------------------------------------------------------- if(NOT MSVC) if(NOT USE_CPP_VERSION) set(USE_CPP_VERSION c++11) endif() message(STATUS "Use C++ version: ${USE_CPP_VERSION}") # following only available from cmake 2.8.12: # add_compile_options(-std=${USE_CPP_VERSION}) # so using this instead: add_definitions(-std=${USE_CPP_VERSION}) endif() #----------------------------------------------------------------------------- # # Compiler and Linker flags # #----------------------------------------------------------------------------- if(MSVC) set(USUAL_COMPILE_OPTIONS "/Ox") else() set(USUAL_COMPILE_OPTIONS "-O3 -g") endif() if(WIN32) add_definitions(-DWIN32 -D_WIN32 -DMSWIN32 -DBGDWIN32) endif() set(CMAKE_CXX_FLAGS_DEV "${USUAL_COMPILE_OPTIONS}" CACHE STRING "Flags used by the compiler during developer builds." FORCE) set(CMAKE_EXE_LINKER_FLAGS_DEV "" CACHE STRING "Flags used by the linker during developer builds." FORCE) mark_as_advanced( CMAKE_CXX_FLAGS_DEV CMAKE_EXE_LINKER_FLAGS_DEV ) set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${USUAL_COMPILE_OPTIONS}" CACHE STRING "Flags used by the compiler during RELWITHDEBINFO builds." FORCE) #----------------------------------------------------------------------------- # # Build Type # #----------------------------------------------------------------------------- add_definitions(${OSMIUM_WARNING_OPTIONS}) # In 'Dev' mode: compile with very strict warnings and turn them into errors. if(CMAKE_BUILD_TYPE STREQUAL "Dev") if(NOT MSVC) add_definitions(-Werror) endif() endif() # Force RelWithDebInfo build type if none was given if(CMAKE_BUILD_TYPE) set(build_type ${CMAKE_BUILD_TYPE}) else() set(build_type "RelWithDebInfo") endif() set(CMAKE_BUILD_TYPE ${build_type} CACHE STRING "Choose the type of build, options are: ${CMAKE_CONFIGURATION_TYPES}." FORCE) message(STATUS "Build Type: ${CMAKE_BUILD_TYPE}") #----------------------------------------------------------------------------- # # Version # #----------------------------------------------------------------------------- find_package(Git) if(GIT_FOUND) execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags --dirty=-changed WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" OUTPUT_VARIABLE VERSION_FROM_GIT ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if(VERSION_FROM_GIT) set(VERSION_FROM_GIT " (${VERSION_FROM_GIT})") endif() endif() configure_file( ${PROJECT_SOURCE_DIR}/src/version.cpp.in ${PROJECT_BINARY_DIR}/src/version.cpp ) #----------------------------------------------------------------------------- configure_file( ${PROJECT_SOURCE_DIR}/osmium-wrapper.in ${PROJECT_BINARY_DIR}/osmium ) include_directories(SYSTEM include) include_directories(${PROJECT_BINARY_DIR}/src) #----------------------------------------------------------------------------- # # Tests # #----------------------------------------------------------------------------- enable_testing() add_subdirectory(test) #----------------------------------------------------------------------------- add_subdirectory(man) add_subdirectory(src) #----------------------------------------------------------------------------- osmium-tool-1.7.1/CONTRIBUTING.md000066400000000000000000000011441315004223400162270ustar00rootroot00000000000000 Some rules for contributing to this project: * Please open a separate issue for each problem, question, or comment you have. Do not re-use existing issues for other topics, even if they are similar. This keeps issues small and manageable and makes it much easier to follow through and make sure each problem is taken care of. If you are reporting a problem: * Describe exactly what you did, what you expected to happen and what did happen instead. Include relevant information about the platform, OS version etc. you are using. Include shell commands you typed in, log files, errors messages etc. osmium-tool-1.7.1/LICENSE-rapidjson.txt000066400000000000000000000070421315004223400176130ustar00rootroot00000000000000Tencent is pleased to support the open source community by making RapidJSON available. Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License. If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. A copy of the MIT License is included in this file. Other dependencies and licenses: Open Source Software Licensed Under the BSD License: -------------------------------------------------------------------- The msinttypes r29 Copyright (c) 2006-2013 Alexander Chemeris All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Terms of the MIT License: -------------------------------------------------------------------- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. osmium-tool-1.7.1/LICENSE.txt000066400000000000000000001045131315004223400156250ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . osmium-tool-1.7.1/Makefile000066400000000000000000000003501315004223400154340ustar00rootroot00000000000000 all: mkdir -p build && cd build && cmake .. && $(MAKE) clean: if test -d build; then cd build && $(MAKE) clean; fi distclean: rm -fr build deb: debuild -I -us -uc test: cd build && ctest .PHONY: clean distclean deb test osmium-tool-1.7.1/README.md000066400000000000000000000074521315004223400152650ustar00rootroot00000000000000 # Osmium Command Line Tool A multipurpose command line tool for working with OpenStreetMap data based on the Osmium library. Official web site: http://osmcode.org/osmium-tool/ [![Build Status](https://secure.travis-ci.org/osmcode/osmium-tool.svg)](http://travis-ci.org/osmcode/osmium-tool) [![Build Status](https://ci.appveyor.com/api/projects/status/github/osmcode/osmium-tool?svg=true)](https://ci.appveyor.com/project/Mapbox/osmium-tool) ## Prerequisites You need a C++11 compliant compiler. GCC 4.8 and later as well as clang 3.6 and later are known to work. It also works on modern Visual Studio C++ compilers. You also need the following libraries: Libosmium (>= 2.13.1) http://osmcode.org/libosmium Debian/Ubuntu: libosmium2-dev Protozero (>= 1.5.1) This is included in the libosmium repository and might or might not have been installed with it. See the libosmium README. https://github.com/mapbox/protozero Debian/Ubuntu: protozero Fedora: protozero-devel Utfcpp This is included in the libosmium repository and might or might not have been installed with it. See the libosmium README. http://utfcpp.sourceforge.net/ Debian/Ubuntu: libutfcpp-dev openSUSE: utfcpp Fedora: utf8cpp-devel RapidJSON (>= 1.1) This is included in the osmium-tool repository, so you usually do not need to install this. http://rapidjson.org/ Debian/Ubuntu: rapidjson-dev boost-program-options (>= 1.55) http://www.boost.org/doc/libs/1_55_0/doc/html/program_options.html Debian/Ubuntu: libboost-program-options-dev boost-crc http://www.boost.org/doc/libs/1_55_0/libs/crc/ Debian/Ubuntu: libboost-dev bz2lib http://www.bzip.org/ Debian/Ubuntu: libbz2-dev Fedora: bzip2-devel CentOS: bzip2-devel zlib http://www.zlib.net/ Debian/Ubuntu: zlib1g-dev openSUSE: zlib-devel Fedora: zlib-devel CentOS: zlib-devel Expat http://expat.sourceforge.net/ Debian/Ubuntu: libexpat1-dev openSUSE: libexpat-devel Fedora: expat-devel CentOS: expat-devel cmake http://www.cmake.org/ Debian/Ubuntu: cmake openSUSE: cmake Fedora: cmake Pandoc (Needed to build documentation, optional) http://johnmacfarlane.net/pandoc/ Debian/Ubuntu: pandoc openSUSE: pandoc Fedora: pandoc ## Building Osmium uses CMake for its builds. For Unix/Linux systems a simple Makefile wrapper is provided to make the build even easier. Just type `make` to compile. Results will be in the `build` directory. Or you can go the long route explicitly calling CMake as follows: mkdir build cd build cmake .. make To set the build type call cmake with `-DCMAKE_BUILD_TYPE=type`. Possible values are empty, Debug, Release, RelWithDebInfo, MinSizeRel, and Dev. The default is RelWithDebInfo. ## Documentation See the [Osmium Tool website](http://osmcode.org/osmium-tool/) and [Osmium Tool Manual](http://osmcode.org/osmium-tool/manual.html). There are man pages in the 'man' directory. To build them you need 'pandoc'. If the `pandoc` command was found during the CMake config step, the manpages will be built automatically. ## Tests Call `ctest` in the build directory to run the tests after build. More extensive tests of the libosmium I/O system can also be run. See `test/io/Makefile.in` for instructions. ## License Copyright (C) 2013-2017 Jochen Topf (jochen@topf.org) This program is available under the GNU GENERAL PUBLIC LICENSE Version 3. See the file LICENSE.txt for the complete text of the license. ## Authors This program was written and is maintained by Jochen Topf (jochen@topf.org). osmium-tool-1.7.1/appveyor.yml000066400000000000000000000010641315004223400163670ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # Configuration for continuous integration service at appveyor.com # #----------------------------------------------------------------------------- environment: matrix: - config: Dev - config: RelWithDebInfo shallow_clone: true # Operating system (build VM template) os: Visual Studio 2015 # scripts that are called at very beginning, before repo cloning init: # clone directory clone_folder: c:\projects\osmium-tool platform: x64 build_script: - build-appveyor.bat osmium-tool-1.7.1/build-appveyor.bat000066400000000000000000000063401315004223400174330ustar00rootroot00000000000000@ECHO OFF SETLOCAL SET EL=0 ECHO ~~~~~~ %~f0 ~~~~~~ SET CUSTOM_CMAKE=cmake-3.6.2-win64-x64 ::show all available env vars SET ECHO cmake on AppVeyor cmake -version ECHO activating VS cmd prompt && CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 IF %ERRORLEVEL% NEQ 0 GOTO ERROR SET otdir=%CD% SET PATH=%otdir%\%CUSTOM_CMAKE%\bin;%PATH% SET LODEPSDIR=%otdir%\libosmium-deps ::libexpat.dll SET PATH=%LODEPSDIR%\expat\lib;%PATH% ::zlibwapi.dll SET PATH=%LODEPSDIR%\zlib\lib;%PATH% ::convert backslashes in bzip2 path to forward slashes ::cmake cannot find it otherwise SET LIBBZIP2=%LODEPSDIR%\bzip2\lib\libbz2.lib SET LIBBZIP2=%LIBBZIP2:\=/% IF NOT EXIST cm.7z ECHO downloading cmake... && powershell Invoke-WebRequest https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/%CUSTOM_CMAKE%.7z -OutFile cm.7z IF %ERRORLEVEL% NEQ 0 GOTO ERROR IF NOT EXIST lodeps.7z ECHO downloading binary dependencies... && powershell Invoke-WebRequest https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/libosmium-deps-win-14.0-x64.7z -OutFile lodeps.7z IF %ERRORLEVEL% NEQ 0 GOTO ERROR IF NOT EXIST %CUSTOM_CMAKE% ECHO extracting cmake... && 7z x cm.7z | %windir%\system32\find "ing archive" IF %ERRORLEVEL% NEQ 0 GOTO ERROR IF NOT EXIST %LODEPSDIR% ECHO extracting binary dependencies... && 7z x lodeps.7z | %windir%\system32\find "ing archive" IF %ERRORLEVEL% NEQ 0 GOTO ERROR ECHO %LODEPSDIR% DIR %LODEPSDIR% ::TREE %LODEPSDIR% ::powershell (Get-ChildItem $env:LODEPSDIR\boost\lib -Filter *boost*.dll)[0].BaseName.split('_')[-1] FOR /F "tokens=1 usebackq" %%i in (`powershell ^(Get-ChildItem %LODEPSDIR%\boost\lib -Filter *boost*.dll^)[0].BaseName.split^('_'^)[-1]`) DO SET BOOST_VERSION=%%i IF %ERRORLEVEL% NEQ 0 GOTO ERROR ECHO BOOST_VERSION^: %BOOST_VERSION% ECHO our own cmake cmake -version CD %otdir%\.. IF NOT EXIST libosmium ECHO cloning libosmium && git clone --depth 1 https://github.com/osmcode/libosmium.git IF %ERRORLEVEL% NEQ 0 GOTO ERROR CD libosmium git fetch IF %ERRORLEVEL% NEQ 0 GOTO ERROR git pull IF %ERRORLEVEL% NEQ 0 GOTO ERROR CD %otdir% IF EXIST build ECHO deleting build dir... && RD /Q /S build IF %ERRORLEVEL% NEQ 0 GOTO ERROR MKDIR build IF %ERRORLEVEL% NEQ 0 GOTO ERROR CD build ECHO config^: %config% SET CMAKE_CMD=cmake .. -LA -G "Visual Studio 14 Win64" ^ -DOsmium_DEBUG=TRUE ^ -DCMAKE_BUILD_TYPE=%config% ^ -DBOOST_ROOT=%LODEPSDIR%\boost ^ -DBoost_PROGRAM_OPTIONS_LIBRARY=%LODEPSDIR%\boost\lib\libboost_program_options-vc140-mt-1_%BOOST_VERSION%.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 ECHO calling^: %CMAKE_CMD% %CMAKE_CMD% IF %ERRORLEVEL% NEQ 0 GOTO ERROR msbuild osmium.sln ^ /p:Configuration=%config% ^ /toolsversion:14.0 ^ /p:Platform=x64 ^ /p:PlatformToolset=v140 IF %ERRORLEVEL% NEQ 0 GOTO ERROR ctest --output-on-failure -C %config% IF %ERRORLEVEL% NEQ 0 GOTO ERROR GOTO DONE :ERROR ECHO ~~~~~~ ERROR %~f0 ~~~~~~ SET EL=%ERRORLEVEL% :DONE IF %EL% NEQ 0 ECHO. && ECHO !!! ERRORLEVEL^: %EL% !!! && ECHO. ECHO ~~~~~~ DONE %~f0 ~~~~~~ EXIT /b %EL% osmium-tool-1.7.1/build-local.bat000066400000000000000000000012011315004223400166470ustar00rootroot00000000000000@ECHO OFF SETLOCAL SET EL=0 ECHO ~~~~~~ %~f0 ~~~~~~ ECHO. ECHO build-local ["config=Dev"] ECHO default config^: RelWithDebInfo ECHO. SET platform=x64 SET config=RelWithDebInfo :: OVERRIDE PARAMETERS >>>>>>>> :NEXT-ARG IF '%1'=='' GOTO ARGS-DONE ECHO setting %1 SET %1 SHIFT GOTO NEXT-ARG :ARGS-DONE ::<<<<< OVERRIDE PARAMETERS WHERE 7z IF %ERRORLEVEL% NEQ 0 ECHO 7zip not on PATH && GOTO ERROR CALL build-appveyor.bat IF %ERRORLEVEL% NEQ 0 GOTO ERROR GOTO DONE :ERROR ECHO ~~~~~~ ERROR %~f0 ~~~~~~ SET EL=%ERRORLEVEL% :DONE IF %EL% NEQ 0 ECHO. && ECHO !!! ERRORLEVEL^: %EL% !!! && ECHO. ECHO ~~~~~~ DONE %~f0 ~~~~~~ EXIT /b %EL% osmium-tool-1.7.1/cmake/000077500000000000000000000000001315004223400150565ustar00rootroot00000000000000osmium-tool-1.7.1/cmake/FindOsmium.cmake000066400000000000000000000322621315004223400201370ustar00rootroot00000000000000#---------------------------------------------------------------------- # # FindOsmium.cmake # # Find the Libosmium headers and, optionally, several components needed # for different Libosmium functions. # #---------------------------------------------------------------------- # # Usage: # # Copy this file somewhere into your project directory, where cmake can # find it. Usually this will be a directory called "cmake" which you can # add to the CMake module search path with the following line in your # CMakeLists.txt: # # list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") # # Then add the following in your CMakeLists.txt: # # find_package(Osmium [version] REQUIRED COMPONENTS ) # include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS}) # # The version number is optional. If it is not set, any version of # libosmium will do. # # For the substitute a space separated list of one or more of the # following components: # # pbf - include libraries needed for PBF input and output # xml - include libraries needed for XML input and output # io - include libraries needed for any type of input/output # geos - include if you want to use any of the GEOS functions # gdal - include if you want to use any of the OGR functions # proj - include if you want to use any of the Proj.4 functions # sparsehash - include if you use the sparsehash index # # You can check for success with something like this: # # if(NOT OSMIUM_FOUND) # message(WARNING "Libosmium not found!\n") # endif() # #---------------------------------------------------------------------- # # Variables: # # OSMIUM_FOUND - True if Osmium found. # OSMIUM_INCLUDE_DIRS - Where to find include files. # OSMIUM_XML_LIBRARIES - Libraries needed for XML I/O. # OSMIUM_PBF_LIBRARIES - Libraries needed for PBF I/O. # OSMIUM_IO_LIBRARIES - Libraries needed for XML or PBF I/O. # OSMIUM_LIBRARIES - All libraries Osmium uses somewhere. # #---------------------------------------------------------------------- # This is the list of directories where we look for osmium and protozero # includes. set(_osmium_include_path ../libosmium ~/Library/Frameworks /Library/Frameworks /opt/local # DarwinPorts /opt ) # Look for the header file. find_path(OSMIUM_INCLUDE_DIR osmium/version.hpp PATH_SUFFIXES include PATHS ${_osmium_include_path} ) # Check libosmium version number if(Osmium_FIND_VERSION) file(STRINGS "${OSMIUM_INCLUDE_DIR}/osmium/version.hpp" _libosmium_version_define REGEX "#define LIBOSMIUM_VERSION_STRING") if("${_libosmium_version_define}" MATCHES "#define LIBOSMIUM_VERSION_STRING \"([0-9.]+)\"") set(_libosmium_version "${CMAKE_MATCH_1}") else() set(_libosmium_version "unknown") endif() endif() set(OSMIUM_INCLUDE_DIRS "${OSMIUM_INCLUDE_DIR}") #---------------------------------------------------------------------- # # Check for optional components # #---------------------------------------------------------------------- if(Osmium_FIND_COMPONENTS) foreach(_component ${Osmium_FIND_COMPONENTS}) string(TOUPPER ${_component} _component_uppercase) set(Osmium_USE_${_component_uppercase} TRUE) endforeach() endif() #---------------------------------------------------------------------- # Component 'io' is an alias for 'pbf' and 'xml' if(Osmium_USE_IO) set(Osmium_USE_PBF TRUE) set(Osmium_USE_XML TRUE) endif() #---------------------------------------------------------------------- # Component 'ogr' is an alias for 'gdal' if(Osmium_USE_OGR) set(Osmium_USE_GDAL TRUE) endif() #---------------------------------------------------------------------- # Component 'pbf' if(Osmium_USE_PBF) find_package(ZLIB) find_package(Threads) message(STATUS "Looking for protozero") find_path(PROTOZERO_INCLUDE_DIR protozero/version.hpp PATH_SUFFIXES include PATHS ${_osmium_include_path} ${OSMIUM_INCLUDE_DIR} ) if(PROTOZERO_INCLUDE_DIR) message(STATUS "Looking for protozero - found") else() message(STATUS "Looking for protozero - not found") endif() list(APPEND OSMIUM_EXTRA_FIND_VARS ZLIB_FOUND Threads_FOUND PROTOZERO_INCLUDE_DIR) if(ZLIB_FOUND AND Threads_FOUND AND PROTOZERO_INCLUDE_DIR) list(APPEND OSMIUM_PBF_LIBRARIES ${ZLIB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) if(WIN32) # This is needed for the ntohl() function list(APPEND OSMIUM_PBF_LIBRARIES ws2_32) endif() list(APPEND OSMIUM_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR} ${PROTOZERO_INCLUDE_DIR} ) else() message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.") endif() endif() #---------------------------------------------------------------------- # Component 'xml' if(Osmium_USE_XML) find_package(EXPAT) find_package(BZip2) find_package(ZLIB) find_package(Threads) list(APPEND OSMIUM_EXTRA_FIND_VARS EXPAT_FOUND BZIP2_FOUND ZLIB_FOUND Threads_FOUND) if(EXPAT_FOUND AND BZIP2_FOUND AND ZLIB_FOUND AND Threads_FOUND) list(APPEND OSMIUM_XML_LIBRARIES ${EXPAT_LIBRARIES} ${BZIP2_LIBRARIES} ${ZLIB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) list(APPEND OSMIUM_INCLUDE_DIRS ${EXPAT_INCLUDE_DIR} ${BZIP2_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ) else() message(WARNING "Osmium: Can not find some libraries for XML input/output, please install them or configure the paths.") endif() endif() #---------------------------------------------------------------------- list(APPEND OSMIUM_IO_LIBRARIES ${OSMIUM_PBF_LIBRARIES} ${OSMIUM_XML_LIBRARIES} ) list(APPEND OSMIUM_LIBRARIES ${OSMIUM_IO_LIBRARIES} ) #---------------------------------------------------------------------- # Component 'geos' if(Osmium_USE_GEOS) find_path(GEOS_INCLUDE_DIR geos/geom.h) find_library(GEOS_LIBRARY NAMES geos) list(APPEND OSMIUM_EXTRA_FIND_VARS GEOS_INCLUDE_DIR GEOS_LIBRARY) if(GEOS_INCLUDE_DIR AND GEOS_LIBRARY) SET(GEOS_FOUND 1) list(APPEND OSMIUM_LIBRARIES ${GEOS_LIBRARY}) list(APPEND OSMIUM_INCLUDE_DIRS ${GEOS_INCLUDE_DIR}) else() message(WARNING "Osmium: GEOS library is required but not found, please install it or configure the paths.") endif() endif() #---------------------------------------------------------------------- # Component 'gdal' (alias 'ogr') if(Osmium_USE_GDAL) find_package(GDAL) list(APPEND OSMIUM_EXTRA_FIND_VARS GDAL_FOUND) if(GDAL_FOUND) list(APPEND OSMIUM_LIBRARIES ${GDAL_LIBRARIES}) list(APPEND OSMIUM_INCLUDE_DIRS ${GDAL_INCLUDE_DIRS}) else() message(WARNING "Osmium: GDAL library is required but not found, please install it or configure the paths.") endif() endif() #---------------------------------------------------------------------- # Component 'proj' if(Osmium_USE_PROJ) find_path(PROJ_INCLUDE_DIR proj_api.h) find_library(PROJ_LIBRARY NAMES proj) list(APPEND OSMIUM_EXTRA_FIND_VARS PROJ_INCLUDE_DIR PROJ_LIBRARY) if(PROJ_INCLUDE_DIR AND PROJ_LIBRARY) set(PROJ_FOUND 1) list(APPEND OSMIUM_LIBRARIES ${PROJ_LIBRARY}) list(APPEND OSMIUM_INCLUDE_DIRS ${PROJ_INCLUDE_DIR}) else() message(WARNING "Osmium: PROJ.4 library is required but not found, please install it or configure the paths.") endif() endif() #---------------------------------------------------------------------- # Component 'sparsehash' if(Osmium_USE_SPARSEHASH) find_path(SPARSEHASH_INCLUDE_DIR google/sparsetable) list(APPEND OSMIUM_EXTRA_FIND_VARS SPARSEHASH_INCLUDE_DIR) if(SPARSEHASH_INCLUDE_DIR) # Find size of sparsetable::size_type. This does not work on older # CMake versions because they can do this check only in C, not in C++. if(NOT CMAKE_VERSION VERSION_LESS 3.0) include(CheckTypeSize) set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR}) set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable") check_type_size("google::sparsetable::size_type" SPARSETABLE_SIZE_TYPE LANGUAGE CXX) set(CMAKE_EXTRA_INCLUDE_FILES) set(CMAKE_REQUIRED_INCLUDES) else() set(SPARSETABLE_SIZE_TYPE ${CMAKE_SIZEOF_VOID_P}) endif() # Sparsetable::size_type must be at least 8 bytes (64bit), otherwise # OSM object IDs will not fit. if(SPARSETABLE_SIZE_TYPE GREATER 7) set(SPARSEHASH_FOUND 1) add_definitions(-DOSMIUM_WITH_SPARSEHASH=${SPARSEHASH_FOUND}) list(APPEND OSMIUM_INCLUDE_DIRS ${SPARSEHASH_INCLUDE_DIR}) else() message(WARNING "Osmium: Disabled Google SparseHash library on 32bit system (size_type=${SPARSETABLE_SIZE_TYPE}).") endif() else() message(WARNING "Osmium: Google SparseHash library is required but not found, please install it or configure the paths.") endif() endif() #---------------------------------------------------------------------- list(REMOVE_DUPLICATES OSMIUM_INCLUDE_DIRS) if(OSMIUM_XML_LIBRARIES) list(REMOVE_DUPLICATES OSMIUM_XML_LIBRARIES) endif() if(OSMIUM_PBF_LIBRARIES) list(REMOVE_DUPLICATES OSMIUM_PBF_LIBRARIES) endif() if(OSMIUM_IO_LIBRARIES) list(REMOVE_DUPLICATES OSMIUM_IO_LIBRARIES) endif() if(OSMIUM_LIBRARIES) list(REMOVE_DUPLICATES OSMIUM_LIBRARIES) endif() #---------------------------------------------------------------------- # # Check that all required libraries are available # #---------------------------------------------------------------------- if(OSMIUM_EXTRA_FIND_VARS) list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS) endif() # Handle the QUIETLY and REQUIRED arguments and the optional version check # 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} VERSION_VAR _libosmium_version) unset(OSMIUM_EXTRA_FIND_VARS) #---------------------------------------------------------------------- # # A function for setting the -pthread option in compilers/linkers # #---------------------------------------------------------------------- function(set_pthread_on_target _target) if(NOT MSVC) set_target_properties(${_target} PROPERTIES COMPILE_FLAGS "-pthread") if(NOT APPLE) set_target_properties(${_target} PROPERTIES LINK_FLAGS "-pthread") endif() endif() endfunction() #---------------------------------------------------------------------- # # Add compiler flags # #---------------------------------------------------------------------- add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64) if(MSVC) add_definitions(-wd4996) # Disable warning C4068: "unknown pragma" because we want it to ignore # pragmas for other compilers. add_definitions(-wd4068) # Disable warning C4715: "not all control paths return a value" because # it generates too many false positives. add_definitions(-wd4715) # Disable warning C4351: new behavior: elements of array '...' will be # default initialized. The new behaviour is correct and we don't support # old compilers anyway. add_definitions(-wd4351) # Disable warning C4503: "decorated name length exceeded, name was truncated" # there are more than 150 of generated names in libosmium longer than 4096 symbols supported in MSVC add_definitions(-wd4503) add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS) endif() if(APPLE) # following only available from cmake 2.8.12: # add_compile_options(-stdlib=libc++) # so using this instead: add_definitions(-stdlib=libc++) set(LDFLAGS ${LDFLAGS} -stdlib=libc++) endif() #---------------------------------------------------------------------- # This is a set of recommended warning options that can be added when compiling # libosmium code. if(MSVC) set(OSMIUM_WARNING_OPTIONS "/W3 /wd4514" CACHE STRING "Recommended warning options for libosmium") else() set(OSMIUM_WARNING_OPTIONS "-Wall -Wextra -pedantic -Wredundant-decls -Wdisabled-optimization -Wctor-dtor-privacy -Wnon-virtual-dtor -Woverloaded-virtual -Wsign-promo -Wold-style-cast" CACHE STRING "Recommended warning options for libosmium") endif() set(OSMIUM_DRACONIC_CLANG_OPTIONS "-Wdocumentation -Wunused-exception-parameter -Wmissing-declarations -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-unused-macros -Wno-exit-time-destructors -Wno-global-constructors -Wno-padded -Wno-switch-enum -Wno-missing-prototypes -Wno-weak-vtables -Wno-cast-align -Wno-float-equal") if(Osmium_DEBUG) message(STATUS "OSMIUM_XML_LIBRARIES=" ${OSMIUM_XML_LIBRARIES}) message(STATUS "OSMIUM_PBF_LIBRARIES=" ${OSMIUM_PBF_LIBRARIES}) message(STATUS "OSMIUM_IO_LIBRARIES=" ${OSMIUM_IO_LIBRARIES}) message(STATUS "OSMIUM_LIBRARIES=" ${OSMIUM_LIBRARIES}) message(STATUS "OSMIUM_INCLUDE_DIRS=" ${OSMIUM_INCLUDE_DIRS}) endif() osmium-tool-1.7.1/cmake/run_test_compare_output.cmake000066400000000000000000000037601315004223400230570ustar00rootroot00000000000000# # First, if variable 'tmpdir' ist set, this directory will be removed with # all its content and recreated. # # Then runs a test command given in the variable 'cmd' in directory 'dir'. # Checks that the return code is 0. # Checks that there is nothing on stderr. # If the variable 'cmd2' is set, the command will be run and checked in the # same manner. # Compares output on stdout with reference file in variable 'reference'. # if(NOT cmd) message(FATAL_ERROR "Variable 'cmd' not defined") endif() if(NOT dir) message(FATAL_ERROR "Variable 'dir' not defined") endif() if(NOT reference) message(FATAL_ERROR "Variable 'reference' not defined") endif() if(NOT output) message(FATAL_ERROR "Variable 'output' not defined") endif() if(tmpdir) file(REMOVE_RECURSE ${tmpdir}) file(MAKE_DIRECTORY ${tmpdir}) endif() message("Executing: ${cmd}") separate_arguments(cmd) execute_process( COMMAND ${cmd} WORKING_DIRECTORY ${dir} RESULT_VARIABLE result OUTPUT_FILE ${output} ERROR_VARIABLE stderr ) if(NOT (stderr STREQUAL "")) message(SEND_ERROR "Command tested wrote to stderr: ${stderr}") endif() if(result) message(FATAL_ERROR "Error when calling '${cmd}': ${result}") endif() if(cmd2) message("Executing: ${cmd2}") separate_arguments(cmd2) execute_process( COMMAND ${cmd2} WORKING_DIRECTORY ${dir} RESULT_VARIABLE result OUTPUT_FILE ${output} ERROR_VARIABLE stderr ) if(NOT (stderr STREQUAL "")) message(SEND_ERROR "Command tested wrote to stderr: ${stderr}") endif() if(result) message(FATAL_ERROR "Error when calling '${cmd}': ${result}") endif() endif() set(compare "${CMAKE_COMMAND} -E compare_files ${reference} ${output}") message("Executing: ${compare}") separate_arguments(compare) execute_process( COMMAND ${compare} RESULT_VARIABLE result ) if(result) message(SEND_ERROR "Test output does not match '${reference}'. Output is in '${output}'.") endif() osmium-tool-1.7.1/export-example-config/000077500000000000000000000000001315004223400202135ustar00rootroot00000000000000osmium-tool-1.7.1/export-example-config/default-config.json000066400000000000000000000006351315004223400240010ustar00rootroot00000000000000 { "attributes": { "type": false, "id": false, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": [], "area_tags": [], "exclude_tags": [], "include_tags": [] } osmium-tool-1.7.1/export-example-config/example-config.json000066400000000000000000000007771315004223400240170ustar00rootroot00000000000000{ "attributes": { "type": true, "id": "@id", "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": ["highway", "barrier", "natural=coastline"], "area_tags": ["aeroway", "amenity", "building", "landuse", "leisure", "man_made", "natural!=coastline"], "exclude_tags": ["created_by", "source", "source:*"], "include_tags": [] } osmium-tool-1.7.1/extract-example-config/000077500000000000000000000000001315004223400203445ustar00rootroot00000000000000osmium-tool-1.7.1/extract-example-config/README.md000066400000000000000000000012741315004223400216270ustar00rootroot00000000000000 # Example config for creating extracts These example files show the different ways the extent of extracts to be created with the `osmium extract` command can be specified. The config file `extracts.json` contains a list of all extracts that should be created. In this case several different parts of Germany. You can [download a Germany extract](http://download.geofabrik.de/europe/germany.html) and then try this out: osmium extract -v -c examples-extract.json germany-latest.osm.pbf All resulting files will be written to the `/tmp/` directory because of the `directory` setting in the config file. You can override this on the command line with the `-d DIR` or `--directory=DIR` option. osmium-tool-1.7.1/extract-example-config/berlin.geojson000066400000000000000000000113341315004223400232070ustar00rootroot00000000000000{ "type": "Feature", "properties": { "name": "Berlin" }, "geometry": { "type": "Polygon", "coordinates": [[ [1.373096E+01, 5.239455E+01], [1.371644E+01, 5.239650E+01], [1.369940E+01, 5.238719E+01], [1.370683E+01, 5.237793E+01], [1.369538E+01, 5.236414E+01], [1.367929E+01, 5.236490E+01], [1.365020E+01, 5.233446E+01], [1.363535E+01, 5.233825E+01], [1.362978E+01, 5.234713E+01], [1.363782E+01, 5.236773E+01], [1.362606E+01, 5.237642E+01], [1.360378E+01, 5.236905E+01], [1.358738E+01, 5.238813E+01], [1.356448E+01, 5.238530E+01], [1.353044E+01, 5.238605E+01], [1.352982E+01, 5.239436E+01], [1.351776E+01, 5.239852E+01], [1.347892E+01, 5.239210E+01], [1.346283E+01, 5.241758E+01], [1.342229E+01, 5.240796E+01], [1.343343E+01, 5.238530E+01], [1.342198E+01, 5.237340E+01], [1.338392E+01, 5.237548E+01], [1.338268E+01, 5.238530E+01], [1.336721E+01, 5.238605E+01], [1.336566E+01, 5.239266E+01], [1.333750E+01, 5.240560E+01], [1.331089E+01, 5.239502E+01], [1.329325E+01, 5.240956E+01], [1.327066E+01, 5.240069E+01], [1.324560E+01, 5.240239E+01], [1.323941E+01, 5.241749E+01], [1.317412E+01, 5.240465E+01], [1.317350E+01, 5.239125E+01], [1.315833E+01, 5.238728E+01], [1.312832E+01, 5.238407E+01], [1.308469E+01, 5.240824E+01], [1.308283E+01, 5.242202E+01], [1.311284E+01, 5.244032E+01], [1.309861E+01, 5.245126E+01], [1.311037E+01, 5.248048E+01], [1.315493E+01, 5.250799E+01], [1.313977E+01, 5.251514E+01], [1.311161E+01, 5.251213E+01], [1.311192E+01, 5.253689E+01], [1.312553E+01, 5.255872E+01], [1.313915E+01, 5.255778E+01], [1.314627E+01, 5.257771E+01], [1.312986E+01, 5.257527E+01], [1.312027E+01, 5.258204E+01], [1.312213E+01, 5.259031E+01], [1.314379E+01, 5.259520E+01], [1.315098E+01, 5.260013E+01], [1.316667E+01, 5.260209E+01], [1.320798E+01, 5.259137E+01], [1.319296E+01, 5.260658E+01], [1.321549E+01, 5.263134E+01], [1.325823E+01, 5.263177E+01], [1.325609E+01, 5.264306E+01], [1.327826E+01, 5.264458E+01], [1.327683E+01, 5.266345E+01], [1.330938E+01, 5.266237E+01], [1.331511E+01, 5.265694E+01], [1.330688E+01, 5.265261E+01], [1.331439E+01, 5.264306E+01], [1.331403E+01, 5.263090E+01], [1.333871E+01, 5.262591E+01], [1.336840E+01, 5.262960E+01], [1.338217E+01, 5.264002E+01], [1.339219E+01, 5.264978E+01], [1.339970E+01, 5.264978E+01], [1.341570E+01, 5.264475E+01], [1.342690E+01, 5.263962E+01], [1.343611E+01, 5.265155E+01], [1.346162E+01, 5.265223E+01], [1.346262E+01, 5.265491E+01], [1.344520E+01, 5.266200E+01], [1.345739E+01, 5.267211E+01], [1.346461E+01, 5.267083E+01], [1.347319E+01, 5.267830E+01], [1.349261E+01, 5.267166E+01], [1.348999E+01, 5.265921E+01], [1.352813E+01, 5.264623E+01], [1.352223E+01, 5.262719E+01], [1.351005E+01, 5.262382E+01], [1.350216E+01, 5.260630E+01], [1.351041E+01, 5.259455E+01], [1.352850E+01, 5.259542E+01], [1.355305E+01, 5.259025E+01], [1.358531E+01, 5.257272E+01], [1.359176E+01, 5.255148E+01], [1.364139E+01, 5.254418E+01], [1.363888E+01, 5.253306E+01], [1.366003E+01, 5.253284E+01], [1.366343E+01, 5.252499E+01], [1.364256E+01, 5.251431E+01], [1.363378E+01, 5.249315E+01], [1.361711E+01, 5.247853E+01], [1.362715E+01, 5.247591E+01], [1.364399E+01, 5.248202E+01], [1.366818E+01, 5.247634E+01], [1.369273E+01, 5.246728E+01], [1.370007E+01, 5.247274E+01], [1.372014E+01, 5.246499E+01], [1.373179E+01, 5.245440E+01], [1.376136E+01, 5.244883E+01], [1.376100E+01, 5.243868E+01], [1.375096E+01, 5.243835E+01], [1.373699E+01, 5.241464E+01], [1.374415E+01, 5.240912E+01], [1.373096E+01, 5.239455E+01] ]] } } osmium-tool-1.7.1/extract-example-config/berlin.poly000066400000000000000000000066021315004223400225300ustar00rootroot00000000000000berlin 1 1.373096E+01 5.239455E+01 1.371644E+01 5.239650E+01 1.369940E+01 5.238719E+01 1.370683E+01 5.237793E+01 1.369538E+01 5.236414E+01 1.367929E+01 5.236490E+01 1.365020E+01 5.233446E+01 1.363535E+01 5.233825E+01 1.362978E+01 5.234713E+01 1.363782E+01 5.236773E+01 1.362606E+01 5.237642E+01 1.360378E+01 5.236905E+01 1.358738E+01 5.238813E+01 1.356448E+01 5.238530E+01 1.353044E+01 5.238605E+01 1.352982E+01 5.239436E+01 1.351776E+01 5.239852E+01 1.347892E+01 5.239210E+01 1.346283E+01 5.241758E+01 1.342229E+01 5.240796E+01 1.343343E+01 5.238530E+01 1.342198E+01 5.237340E+01 1.338392E+01 5.237548E+01 1.338268E+01 5.238530E+01 1.336721E+01 5.238605E+01 1.336566E+01 5.239266E+01 1.333750E+01 5.240560E+01 1.331089E+01 5.239502E+01 1.329325E+01 5.240956E+01 1.327066E+01 5.240069E+01 1.324560E+01 5.240239E+01 1.323941E+01 5.241749E+01 1.317412E+01 5.240465E+01 1.317350E+01 5.239125E+01 1.315833E+01 5.238728E+01 1.312832E+01 5.238407E+01 1.308469E+01 5.240824E+01 1.308283E+01 5.242202E+01 1.311284E+01 5.244032E+01 1.309861E+01 5.245126E+01 1.311037E+01 5.248048E+01 1.315493E+01 5.250799E+01 1.313977E+01 5.251514E+01 1.311161E+01 5.251213E+01 1.311192E+01 5.253689E+01 1.312553E+01 5.255872E+01 1.313915E+01 5.255778E+01 1.314627E+01 5.257771E+01 1.312986E+01 5.257527E+01 1.312027E+01 5.258204E+01 1.312213E+01 5.259031E+01 1.314379E+01 5.259520E+01 1.315098E+01 5.260013E+01 1.316667E+01 5.260209E+01 1.320798E+01 5.259137E+01 1.319296E+01 5.260658E+01 1.321549E+01 5.263134E+01 1.325823E+01 5.263177E+01 1.325609E+01 5.264306E+01 1.327826E+01 5.264458E+01 1.327683E+01 5.266345E+01 1.330938E+01 5.266237E+01 1.331511E+01 5.265694E+01 1.330688E+01 5.265261E+01 1.331439E+01 5.264306E+01 1.331403E+01 5.263090E+01 1.333871E+01 5.262591E+01 1.336840E+01 5.262960E+01 1.338217E+01 5.264002E+01 1.339219E+01 5.264978E+01 1.339970E+01 5.264978E+01 1.341570E+01 5.264475E+01 1.342690E+01 5.263962E+01 1.343611E+01 5.265155E+01 1.346162E+01 5.265223E+01 1.346262E+01 5.265491E+01 1.344520E+01 5.266200E+01 1.345739E+01 5.267211E+01 1.346461E+01 5.267083E+01 1.347319E+01 5.267830E+01 1.349261E+01 5.267166E+01 1.348999E+01 5.265921E+01 1.352813E+01 5.264623E+01 1.352223E+01 5.262719E+01 1.351005E+01 5.262382E+01 1.350216E+01 5.260630E+01 1.351041E+01 5.259455E+01 1.352850E+01 5.259542E+01 1.355305E+01 5.259025E+01 1.358531E+01 5.257272E+01 1.359176E+01 5.255148E+01 1.364139E+01 5.254418E+01 1.363888E+01 5.253306E+01 1.366003E+01 5.253284E+01 1.366343E+01 5.252499E+01 1.364256E+01 5.251431E+01 1.363378E+01 5.249315E+01 1.361711E+01 5.247853E+01 1.362715E+01 5.247591E+01 1.364399E+01 5.248202E+01 1.366818E+01 5.247634E+01 1.369273E+01 5.246728E+01 1.370007E+01 5.247274E+01 1.372014E+01 5.246499E+01 1.373179E+01 5.245440E+01 1.376136E+01 5.244883E+01 1.376100E+01 5.243868E+01 1.375096E+01 5.243835E+01 1.373699E+01 5.241464E+01 1.374415E+01 5.240912E+01 1.373096E+01 5.239455E+01 END END osmium-tool-1.7.1/extract-example-config/brandenburg.poly000066400000000000000000000202651315004223400235470ustar00rootroot00000000000000brandenburg 1 1.441545E+01 5.335626E+01 1.442177E+01 5.334259E+01 1.442438E+01 5.330853E+01 1.443556E+01 5.328224E+01 1.445028E+01 5.327896E+01 1.445852E+01 5.326018E+01 1.445867E+01 5.325950E+01 1.441916E+01 5.321890E+01 1.441332E+01 5.320919E+01 1.440992E+01 5.320568E+01 1.438822E+01 5.319557E+01 1.438151E+01 5.316430E+01 1.439742E+01 5.314588E+01 1.439749E+01 5.314562E+01 1.435989E+01 5.304827E+01 1.432616E+01 5.303146E+01 1.422813E+01 5.298549E+01 1.417930E+01 5.297135E+01 1.415209E+01 5.295518E+01 1.415917E+01 5.294373E+01 1.415730E+01 5.293272E+01 1.417021E+01 5.290097E+01 1.417420E+01 5.288214E+01 1.416930E+01 5.286883E+01 1.414617E+01 5.285209E+01 1.413270E+01 5.284332E+01 1.414575E+01 5.283296E+01 1.416212E+01 5.283086E+01 1.416317E+01 5.283033E+01 1.419051E+01 5.282722E+01 1.421769E+01 5.282373E+01 1.431225E+01 5.276656E+01 1.436309E+01 5.275281E+01 1.444839E+01 5.268275E+01 1.446853E+01 5.267235E+01 1.447787E+01 5.265942E+01 1.454210E+01 5.263904E+01 1.461005E+01 5.260747E+01 1.464806E+01 5.257506E+01 1.465434E+01 5.256837E+01 1.462299E+01 5.252690E+01 1.461805E+01 5.252054E+01 1.461815E+01 5.252049E+01 1.461727E+01 5.251933E+01 1.465200E+01 5.249693E+01 1.458605E+01 5.243059E+01 1.455463E+01 5.242273E+01 1.455299E+01 5.241025E+01 1.455144E+01 5.240951E+01 1.455257E+01 5.240699E+01 1.455099E+01 5.239495E+01 1.457981E+01 5.234623E+01 1.459682E+01 5.230829E+01 1.460039E+01 5.228483E+01 1.464619E+01 5.227555E+01 1.470427E+01 5.226275E+01 1.472857E+01 5.222906E+01 1.470984E+01 5.210710E+01 1.474099E+01 5.209762E+01 1.477307E+01 5.206171E+01 1.477481E+01 5.205944E+01 1.472869E+01 5.200424E+01 1.472844E+01 5.199795E+01 1.472809E+01 5.199750E+01 1.472681E+01 5.195713E+01 1.472507E+01 5.191376E+01 1.460713E+01 5.183235E+01 1.461182E+01 5.183035E+01 1.460812E+01 5.182766E+01 1.465952E+01 5.180085E+01 1.467236E+01 5.174483E+01 1.468006E+01 5.173953E+01 1.468176E+01 5.173411E+01 1.474087E+01 5.169769E+01 1.475505E+01 5.168793E+01 1.477871E+01 5.161530E+01 1.477770E+01 5.161427E+01 1.474431E+01 5.158065E+01 1.470138E+01 5.157814E+01 1.467680E+01 5.154666E+01 1.460047E+01 5.153708E+01 1.457992E+01 5.155990E+01 1.452708E+01 5.154210E+01 1.445223E+01 5.153069E+01 1.436783E+01 5.151288E+01 1.436013E+01 5.149552E+01 1.432343E+01 5.149552E+01 1.432196E+01 5.151060E+01 1.417189E+01 5.153297E+01 1.416491E+01 5.151311E+01 1.413446E+01 5.151356E+01 1.411960E+01 5.147313E+01 1.402236E+01 5.136810E+01 1.397466E+01 5.137199E+01 1.397392E+01 5.138940E+01 1.392108E+01 5.137153E+01 1.377577E+01 5.135252E+01 1.354919E+01 5.136237E+01 1.342957E+01 5.142808E+01 1.328609E+01 5.137520E+01 1.322353E+01 5.138768E+01 1.317436E+01 5.142773E+01 1.317820E+01 5.154040E+01 1.307596E+01 5.159534E+01 1.302394E+01 5.165302E+01 1.314162E+01 5.171829E+01 1.310569E+01 5.185316E+01 1.302518E+01 5.186272E+01 1.266842E+01 5.198572E+01 1.262506E+01 5.196741E+01 1.250800E+01 5.197198E+01 1.233086E+01 5.202918E+01 1.216859E+01 5.216730E+01 1.225778E+01 5.234398E+01 1.225034E+01 5.242790E+01 1.228131E+01 5.246263E+01 1.210789E+01 5.250488E+01 1.214133E+01 5.264039E+01 1.219088E+01 5.265354E+01 1.215124E+01 5.272562E+01 1.219584E+01 5.281032E+01 1.217850E+01 5.284325E+01 1.209426E+01 5.282753E+01 1.206453E+01 5.285971E+01 1.196667E+01 5.285522E+01 1.177590E+01 5.290008E+01 1.177900E+01 5.293145E+01 1.143711E+01 5.304107E+01 1.133677E+01 5.301350E+01 1.122404E+01 5.309466E+01 1.125006E+01 5.315041E+01 1.150772E+01 5.316304E+01 1.150524E+01 5.322909E+01 1.170096E+01 5.327282E+01 1.175547E+01 5.325503E+01 1.197348E+01 5.332612E+01 1.201065E+01 5.338859E+01 1.224972E+01 5.337972E+01 1.251110E+01 5.328578E+01 1.269939E+01 5.327319E+01 1.280220E+01 5.323205E+01 1.301279E+01 5.321500E+01 1.308835E+01 5.326170E+01 1.344759E+01 5.332168E+01 1.350952E+01 5.341850E+01 1.372259E+01 5.352541E+01 1.375851E+01 5.357840E+01 1.382788E+01 5.357546E+01 1.390964E+01 5.351731E+01 1.394680E+01 5.346056E+01 1.407191E+01 5.344876E+01 1.411899E+01 5.346498E+01 1.424782E+01 5.345392E+01 1.426144E+01 5.337640E+01 1.414624E+01 5.329059E+01 1.423791E+01 5.328689E+01 1.429860E+01 5.333056E+01 1.441545E+01 5.335626E+01 END !berlin 1.373096E+01 5.239455E+01 1.371644E+01 5.239650E+01 1.369940E+01 5.238719E+01 1.370683E+01 5.237793E+01 1.369538E+01 5.236414E+01 1.367929E+01 5.236490E+01 1.365020E+01 5.233446E+01 1.363535E+01 5.233825E+01 1.362978E+01 5.234713E+01 1.363782E+01 5.236773E+01 1.362606E+01 5.237642E+01 1.360378E+01 5.236905E+01 1.358738E+01 5.238813E+01 1.356448E+01 5.238530E+01 1.353044E+01 5.238605E+01 1.352982E+01 5.239436E+01 1.351776E+01 5.239852E+01 1.347892E+01 5.239210E+01 1.346283E+01 5.241758E+01 1.342229E+01 5.240796E+01 1.343343E+01 5.238530E+01 1.342198E+01 5.237340E+01 1.338392E+01 5.237548E+01 1.338268E+01 5.238530E+01 1.336721E+01 5.238605E+01 1.336566E+01 5.239266E+01 1.333750E+01 5.240560E+01 1.331089E+01 5.239502E+01 1.329325E+01 5.240956E+01 1.327066E+01 5.240069E+01 1.324560E+01 5.240239E+01 1.323941E+01 5.241749E+01 1.317412E+01 5.240465E+01 1.317350E+01 5.239125E+01 1.315833E+01 5.238728E+01 1.312832E+01 5.238407E+01 1.308469E+01 5.240824E+01 1.308283E+01 5.242202E+01 1.311284E+01 5.244032E+01 1.309861E+01 5.245126E+01 1.311037E+01 5.248048E+01 1.315493E+01 5.250799E+01 1.313977E+01 5.251514E+01 1.311161E+01 5.251213E+01 1.311192E+01 5.253689E+01 1.312553E+01 5.255872E+01 1.313915E+01 5.255778E+01 1.314627E+01 5.257771E+01 1.312986E+01 5.257527E+01 1.312027E+01 5.258204E+01 1.312213E+01 5.259031E+01 1.314379E+01 5.259520E+01 1.315098E+01 5.260013E+01 1.316667E+01 5.260209E+01 1.320798E+01 5.259137E+01 1.319296E+01 5.260658E+01 1.321549E+01 5.263134E+01 1.325823E+01 5.263177E+01 1.325609E+01 5.264306E+01 1.327826E+01 5.264458E+01 1.327683E+01 5.266345E+01 1.330938E+01 5.266237E+01 1.331511E+01 5.265694E+01 1.330688E+01 5.265261E+01 1.331439E+01 5.264306E+01 1.331403E+01 5.263090E+01 1.333871E+01 5.262591E+01 1.336840E+01 5.262960E+01 1.338217E+01 5.264002E+01 1.339219E+01 5.264978E+01 1.339970E+01 5.264978E+01 1.341570E+01 5.264475E+01 1.342690E+01 5.263962E+01 1.343611E+01 5.265155E+01 1.346162E+01 5.265223E+01 1.346262E+01 5.265491E+01 1.344520E+01 5.266200E+01 1.345739E+01 5.267211E+01 1.346461E+01 5.267083E+01 1.347319E+01 5.267830E+01 1.349261E+01 5.267166E+01 1.348999E+01 5.265921E+01 1.352813E+01 5.264623E+01 1.352223E+01 5.262719E+01 1.351005E+01 5.262382E+01 1.350216E+01 5.260630E+01 1.351041E+01 5.259455E+01 1.352850E+01 5.259542E+01 1.355305E+01 5.259025E+01 1.358531E+01 5.257272E+01 1.359176E+01 5.255148E+01 1.364139E+01 5.254418E+01 1.363888E+01 5.253306E+01 1.366003E+01 5.253284E+01 1.366343E+01 5.252499E+01 1.364256E+01 5.251431E+01 1.363378E+01 5.249315E+01 1.361711E+01 5.247853E+01 1.362715E+01 5.247591E+01 1.364399E+01 5.248202E+01 1.366818E+01 5.247634E+01 1.369273E+01 5.246728E+01 1.370007E+01 5.247274E+01 1.372014E+01 5.246499E+01 1.373179E+01 5.245440E+01 1.376136E+01 5.244883E+01 1.376100E+01 5.243868E+01 1.375096E+01 5.243835E+01 1.373699E+01 5.241464E+01 1.374415E+01 5.240912E+01 1.373096E+01 5.239455E+01 END END osmium-tool-1.7.1/extract-example-config/extracts.json000066400000000000000000000112031315004223400230710ustar00rootroot00000000000000{ "directory": "/tmp/", "extracts": [ { "output": "dresden.osm.pbf", "output_format": "pbf", "description": "City of Dresden specified using a bounding box (object format)", "bbox": { "left": 13.57, "right": 13.97, "top": 51.18, "bottom": 50.97 } }, { "output": "munich.osm.pbf", "description": "City of Munich specified using a bounding box (array format)", "bbox": [11.35, 48.05, 11.73, 48.25] }, { "output": "berlin.osm.pbf", "description": "Berlin area specified using a GeoJSON file", "polygon": { "file_name": "berlin.geojson", "file_type": "geojson" } }, { "output": "brandenburg.osm.pbf", "description": "Brandenburg area without Berlin specified using a poly file with hole", "multipolygon": { "file_name": "brandenburg.poly" } }, { "output": "karlsruhe.osm.pbf", "description": "City of Karlsruhe specified using an OSM file", "polygon": { "file_name": "karlsruhe.osm.bz2", "file_type": "osm" } }, { "output": "hamburg.osm.pbf", "description": "City of Hamburg specified using an inline polygon description", "polygon": [[ [9.613465, 53.58071], [9.647599, 53.59655], [9.649288, 53.61059], [9.710458, 53.62282], [9.748647, 53.62482], [9.755407, 53.63184], [9.779739, 53.63144], [9.780077, 53.62041], [9.803734, 53.61340], [9.810156, 53.60498], [9.802720, 53.60237], [9.821984, 53.59114], [9.836178, 53.60137], [9.850034, 53.60578], [9.868622, 53.62402], [9.886112, 53.63481], [9.900712, 53.66354], [9.976046, 53.65593], [9.983638, 53.68637], [10.04788, 53.68845], [10.05897, 53.71541], [10.07883, 53.72889], [10.11328, 53.72232], [10.16292, 53.74650], [10.20263, 53.73511], [10.19037, 53.70193], [10.17343, 53.70193], [10.16117, 53.67980], [10.19621, 53.66665], [10.20964, 53.64485], [10.23417, 53.63793], [10.22483, 53.61957], [10.21431, 53.61957], [10.20322, 53.61091], [10.21023, 53.57902], [10.16467, 53.57625], [10.15825, 53.56827], [10.16876, 53.56030], [10.16818, 53.55197], [10.16000, 53.54573], [10.18803, 53.51830], [10.21373, 53.52733], [10.24643, 53.49364], [10.30542, 53.45715], [10.33637, 53.45298], [10.32381, 53.42863], [10.26775, 53.41297], [10.24672, 53.38581], [10.16789, 53.38929], [10.10073, 53.42167], [10.06452, 53.44776], [9.982178, 53.40496], [9.945679, 53.41784], [9.915895, 53.40879], [9.892536, 53.41645], [9.907135, 53.44046], [9.896624, 53.44672], [9.871512, 53.43524], [9.872680, 53.42584], [9.855160, 53.42306], [9.788586, 53.46723], [9.787418, 53.48704], [9.773986, 53.48739], [9.750627, 53.50893], [9.754714, 53.54850], [9.693980, 53.55267], [9.613465, 53.58071] ]] }, { "output": "cologne.osm.pbf", "description": "City of Cologne suburbs without city center specified using an inline multipolygon description", "multipolygon": [[[ [6.847, 50.987], [6.910, 51.007], [7.037, 50.953], [6.967, 50.880], [6.842, 50.925], [6.847, 50.987] ],[ [6.967, 50.954], [6.969, 50.920], [6.932, 50.928], [6.934, 50.950], [6.967, 50.954] ]]] } ] } osmium-tool-1.7.1/extract-example-config/hamburg.poly000066400000000000000000000040571315004223400227040ustar00rootroot00000000000000hamburg 1 9.613465E+00 5.358071E+01 9.647599E+00 5.359655E+01 9.649288E+00 5.361059E+01 9.710458E+00 5.362282E+01 9.748647E+00 5.362482E+01 9.755407E+00 5.363184E+01 9.779739E+00 5.363144E+01 9.780077E+00 5.362041E+01 9.803734E+00 5.361340E+01 9.810156E+00 5.360498E+01 9.802720E+00 5.360237E+01 9.821984E+00 5.359114E+01 9.836178E+00 5.360137E+01 9.850034E+00 5.360578E+01 9.868622E+00 5.362402E+01 9.886112E+00 5.363481E+01 9.900712E+00 5.366354E+01 9.976046E+00 5.365593E+01 9.983638E+00 5.368637E+01 1.004788E+01 5.368845E+01 1.005897E+01 5.371541E+01 1.007883E+01 5.372889E+01 1.011328E+01 5.372232E+01 1.016292E+01 5.374650E+01 1.020263E+01 5.373511E+01 1.019037E+01 5.370193E+01 1.017343E+01 5.370193E+01 1.016117E+01 5.367980E+01 1.019621E+01 5.366665E+01 1.020964E+01 5.364485E+01 1.023417E+01 5.363793E+01 1.022483E+01 5.361957E+01 1.021431E+01 5.361957E+01 1.020322E+01 5.361091E+01 1.021023E+01 5.357902E+01 1.016467E+01 5.357625E+01 1.015825E+01 5.356827E+01 1.016876E+01 5.356030E+01 1.016818E+01 5.355197E+01 1.016000E+01 5.354573E+01 1.018803E+01 5.351830E+01 1.021373E+01 5.352733E+01 1.024643E+01 5.349364E+01 1.030542E+01 5.345715E+01 1.033637E+01 5.345298E+01 1.032381E+01 5.342863E+01 1.026775E+01 5.341297E+01 1.024672E+01 5.338581E+01 1.016789E+01 5.338929E+01 1.010073E+01 5.342167E+01 1.006452E+01 5.344776E+01 9.982178E+00 5.340496E+01 9.945679E+00 5.341784E+01 9.915895E+00 5.340879E+01 9.892536E+00 5.341645E+01 9.907135E+00 5.344046E+01 9.896624E+00 5.344672E+01 9.871512E+00 5.343524E+01 9.872680E+00 5.342584E+01 9.855160E+00 5.342306E+01 9.788586E+00 5.346723E+01 9.787418E+00 5.348704E+01 9.773986E+00 5.348739E+01 9.750627E+00 5.350893E+01 9.754714E+00 5.354850E+01 9.693980E+00 5.355267E+01 9.613465E+00 5.358071E+01 END END osmium-tool-1.7.1/extract-example-config/karlsruhe.osm.bz2000066400000000000000000000404321315004223400235630ustar00rootroot00000000000000BZh61AY&SYm³Òz_Yé'ÓóÓG<Ë/<Úr2˜u{8²1<£UdݽzÄ£{¦¹Í‹]Âj ‚èvG¤jÉŽ5€Î †ÜáV‰ÙVcÛZc‰[XíRÞÑÔQò{ÓFdh2vîž<5Ћ¸°NÚ¼c:ŸnÃG=ÊN¯£Ós®^õ«sp!;\ÛÐN7tª–«Øê‰eÞfºN£Ç††­Z;˜=ZøÞZéJAT>FbÒvC„”[K'k Yr!+£Q+ÜBª§Ü§8xnººÜ½J±“ν&cy·S%-²]íµ]–™ Ï6èÐ{r»ak"W®üë¤Ëöþƒ~ƒ·TdŸ¾’Ä{ôIÁ¶”1½ëÏ,Å0èÄLwUxuEÚµe®s!²M…XŽn8Ø[¸é'vWœ5iiš©6…$&á·â¸cIÎõDé%(ø9ºêÁ3›S-BŒCbž¡B ¸cfäj*TÄç_sihÉ´3™Lµ·yG0æ½DίZ¥9o-­›.ß«v9`V§`x»U§/¥°+u5š+9çfrnLÄZº×WV✌©okMŒu©‡ y™v C}jõÁáLس®Ë=V®qEV»FAÛs°V¬º‹Lç×Ñnù뾚C™5ʾ!çPtyõ¼0¯eÑo ʵÃêƒÄ ÒHJ ÈnÌ©@A›í—ëFï#²´0œ»DfÌPrŒZ¢—-§ÚL¥—ÐãLr•5ÑJ:¦× Í1#IKS—=ò\‹Ržê‘bÌh’Wj‚zù*0êy¶ª7U”bÐO ,ÔÁÏvÌêî&Ù¨• ]R•t’4 …$vRIuYx¶lå\úÅg"TâšœGS-$Žik¼˜FŠÕGfÕšN’Pwuº8õݺzEåØ{„ë¼õ§u©J•mfÞíÃb;Ȫ¯Ø² Rî$Uv(½ ø%Q’©-Of%yER¢jÐÛ˜pãV5dº­T¨f^ÄÖxÑJåÞ<»‰i†ÞìÍPY}aÃí ‘/]Ú¼³ìË–4·l`·E[mhKMáÁ‚žcNŽ'—¯r²ÉÀ"Ý{±+UTÒBÑ!ö,ÒèF3Ÿ^%´.Öš«oq î*’åÍ'.{*f[5·y¤‰—¦/V±J²ô: +·/(UÍÃtŠUH‡#Ç.ËjÂN Ó˜]-Äfᔪflœî8˧ްåeÌn“iKšS;×D½ë¹¹u$á‚Öž¹2ÊÆ¯§:Qm)gòä(‚ õŸ…»sSOÃKãfÓW&Š'§Zc¥Ïm‘P§wìzv¬»ÙºÜ¶»½¾×>ùîr]ÙÃ,»Z¯è[·Ý÷=ÝWw«°ïpŠ—ímM=<î†<%å°tèª)âx…áAð׈(Ï‚iÀ3Ï\nò¯Lêƒ7{Nâ®]‘›SELÃ)] µ7UTÕ¯]•’ò§¦µ½œñÄ ·œé”©)Í ]TG íó7rwnõqç6¢¼ÂØxcêW«/dJ¦A…-ÊÍT ³X“´îÒ«º©[ƒzô¥nå×$¯³¼.ʳIð}Y@6R>ë®sX¾×ê­åEvÝ^Èù¦H®»p#wÁ¨˜·[ט;%æ>ƒ·ØãÚì³Ú–ÛÌÃõ•ÓOH]V=XŸ&d`îÍÝ#pB1ܼ•Õ‹ƒŒWiªÚ\‹êb¢;żîT¯ÜE5 L-]õsÆß¨åM¡N´§tòAUlî”…ÝÙvæC±S’®—BX©B êUÃYX’˜k–¼Îì–vTí˜ò›w—úž w‡5Gnªî 99Ö§ò0t2¬uŠgEe¦8ó»]ËÊ·r[xºÌkK*»*\0fîó1^£±´Ð†¢žO JF®ª˜8¾××1õwbÌ4­w@r²³9c'²¨V*œž-«ìÑ›”Œ|²ª0޼ÈsU7œØckÉØ/¦<®5Ø©^Z$(fÝX(o* ž9ΑŒÕÉÈ zl0Dºx¼íÍЫ¾žgEâÕD'=Y±á㘗[+²¾×à¶Â’ 2HHðo_Ηuî6|þ°ûññ@´ŠŸ“ŠÆ3±ëè<èß RŸ‡ƒu¬ = ÷›ÛóùÂx8ù½èÌúНQê|êÆqT‹Pk^^˺ êXRtêZbáËO.1nšWZ^£ Œ*dUq1K[-¤l´VêËrRËvÊ¥Flö²´®0®3©fÏ+Æän”˜)\õm´îkVMbÍïÄ™RßKx·-G]l‚öI+on­Öï]î¼æÊá;€]E €¦jVagÊ‚Âp­"³%Õfù ³/0È,å HeÒÃR´ë‚”މ˜-ù»ÉWry1˜­£­š/)^ÝÒ[Q¹[X*f 5Y½DÚÕ´³&¯$ 1˜eŒ7©YÂÙ-e,Ê­Ý5VŽ`ª“mÀ°¡ÈF™t]°q*Í)pÛ•xñ¬˜˜&$’™”Ö]ž<1¨L:†â,Tñ§XT¬²êaÔ¼ªM9œ9d'6Ü/DbÜ[Z•KÒ·kÚ4ÔNªÐÜšâ @’R¨¡„¦¢(N]¦Ô¨…\Éx ɨ¡ÖfS´Š}^À‚ h¥È§ )Û@{hð{Žpy9çù<«Ï1üËùÂy«Š¼•è8«&ý0ªë¥ Z¼º‚]ÁÛ—kC{3¬ê5vrtHõgZ˜ŽÒ t«dt4ë’6÷0íޑ˃®9‡•m)Bâ&Ç<йÐJíÛëΆáw¶6B›pí\A{W/à~jy§·ß³ñU—{¹êƒñQ*™"‡LË„§ññ{Öï‚-pÔª´®àÅáÌ}¤¿„ Ù¥SÂÈ" ^dÊC¨høw&ÚÚ-$iŸ%Ó'Ö˜gh?¼6Šôìie"‰%Dšë/£êD—· £8ØÓyG+>Sç”÷5Ñ"­' Õ§è°ƒ !âåLLACãLkM8÷QÔLðÍŸL%Zü¸Dûà‡}ìh¤{Ÿ6kšE}–û.;qT¥½wÑ ‡Ò*Š*õðê@‰Ä4“À¶Ø½%œpŠu¯¦\®'ܸŒ1ÔÒé¿|„.†Å‹R9KbÇFŒbh˜E®„ 5é Ò‹¢£Ýió-¶az>-­×²\ø=ÓAHV‡¬vóMÒY•,&)1qNzw+w»:Á(ÄÀsœ»¡ŽâÜÏ6ÁÆ„rqëQ„¨YÊvðÚdfÙvuPØô!läÛçk¶ZXRvÜ‹ ’G…|@›$†ºòiŒ…ºT¿ ›kr´ŒÄ+'Z0 Á¾ëΧÕKµÔE ˆ'™¨ZC>˜8Y %ÇS©èí³ï#ÇÖ½â”1I)ƽߌ›öYëg¨Ÿ¸“+tÊÇ×öV«`†‘D”«¤×ÂÓÒU^§ ’€g”DÂåîˆf·T¦2=Cµ÷%›‚>ȱ¹$ò‚¾ IÈRÀšäͨ=‰o·nšfF-/Eô/±uBù|2uPü6Ï>¡—ññôÒáÑvZÙµ2Çk—ÖIä0§Ò϶ë6ŸTª®oª$ë*„»‰Ú÷‡Å»0e:}H.²;ÃqÌZ)ˆZN3$˜á[PÛ¨s…ç ”…c ¢È\“ƒYõ6ûMHWLMa•…làƒ¨úkÆ“ò) ‡&ŽE‹Äš]zS¬hQ\ýGIï‡H^O—ÂŽ5‹ï®l_8“8Úûlæ3enô>w®EI‚”Íc¦ú6¢ Ž$GPH{Š/ç°Í㊼¯µý‰äñê”)ñ®2GQP{^VÒÙmí`ìk²`Æ--Ú­rS vŸÅÝã8S´qæ÷ÇQ"•ÚˆH(Å)-É,8G!üùÆU!J"hÏLÐ!y? ¡!r.·6jKÀ¼q(§–íN šÛ8`„† µGi¥Ù†—É‹ÕìƒEVøÚÒŸÊ_‹b,±W%õ#ä­–Z9cS ²lnáB³6lQ*­ÌΔÇzž«3|É]À³WHõ9ìÀX))“Dö{zŠª›Ý`w‘Ó‘=br ÷]N&AjÝÍQKnðiÅm÷/|4g¡=Ù[(2¸ÖñxJïÑú?•ÂPÚüIsï’°Yáúe ×^x{·OÆ„îžq•ñí6gIäŒ~>uó«Ü»÷qÕà›(ö/|EEày¼ßè"w`ÚåQLËš‰©ªqI¹©6uT¯’ñŸ@%H”ê~ážqPüÆv|¬üÃ?U†…vfÁY“*d";6æÒ ÎKáÞ6,e1aãI‰aýiÕ‚Üí˜kw3ráÇÕÁZ»éG —2Ý Ã»W,÷uí+OÊ´àˆÃÑÕÖÜNéÝÙTSjl*”ÔB[j!§»:Ã{vVõ3À¸ès뙬îÕâÓŠ¡Âꬌ®ìq‘cŽ-â’ÍÝÇÛ玪ì´ð]Z|xúGË(‘y:„Ø \{+“…ì¬Ê8/lI81ofoi=eÂì¢_e·ª»Ë»9K7;2;Rùð+yr†)שª¡Ð°f>ÌÊî½³ÂÐÞ‡UÚé@öÓĘ*VЗH"ûÝæ8Uvnc«Î¾7Ôwßùݬñäˆ:kDž䋳6Zvá›2‚bq$žQ¢ZüT1×a{<¼±a"0¨]Ž¢¦Ç”)íå¨ùb(w½,†`µƒÅÐwÔ^´f/!ªFù)ÊM¶Ës4yw<©›$S‘7œæ±±‹FËn‹®]T5BV»ã£Øz›Ù9Õ%}ê=Fi5 aŸ…b9z²Å@ *¹_#m3>h¹í*¾¶¹p©ÑöÒ=vš¹>˜E"ÚMu1ñ†hÁ¢ÆmÞ…3ä;ÖWRé«;¼jK» ån䔯¦uñå:æªâ²ÀU€èÉDÕh„u™šÕp״̧¤ÐùTRõµ=ÃÎg £Û(±¹–QÅi>g**¾ˆ“¦O΂áì…ߪÚM°­.#‹˜ÁAHºíÌ2Ûí^£b¬Ñmœ:\lÁÏH´Dó‘ÈÚWRM¤¡¹Ÿ!–{Ìë .dõ Ȥť³®µ{Çš9žÁqž†„g%ÃŒD|gËÔ±ð˜A÷*ÓÛ‹´û@^n©K~'MŒ+“{¿]Æ_d"¢÷+=µi8ß‚F‡›­xOz£o·!º²ììÌN¸&Ð@ŠY‘Þ¼B÷ª¬r)•%Ï"õö$ZõYBüD\—™ _y§ñ&¡"OBP‘»Í:’ª²¬ÌÎâéîö®ØK%V»nbV&íy+’†f›JÕ(Ûƒ\6Ù'* ‰³Ôçµ°’àj…UâÞSn蜆ˆåa»»aJZm{N—)ñǸõÑ/ZñC­b™j¿›ê{YS•ª›“†Üè©ïÜrJØ5oUåÈÑ*ÜÒ˜ƒªÌëVŒNÁí^m5‹!uœÕïP¡’M*]ÉU mš£ÑZ= ±Û ƒŽmDën*hãÚ«ÕUWHÖ»Í8àãçy3AÆ.±ìOIÃƘ¾^ç·«S<ß[²ÂØYQs©fëo0†ŽC)°våØoÚÛJL§/P[aÅ\!‰%W‘¶ŠU9ŒKÔ#A„ëgl^l´‹~JYv‘jµ9ì…ÖñÃÂÄ míÙ‚!Yi¤ 6!G0Gè"ñŸ,ÃìáG¡W!Ù/âÄãUXÇL¢Š-ÓÖýr¦„Q“Îv•DJ¹¬ã®®!@'¨´ŽÈ¤å¥S€½s®BŒy‡uHö®^nK/ÛÒÂy ßg‰÷§ŠÒ)å¨~˜mõL+<äá˜íîÌ‹9TÆë<‘î'sŒ˜˜I¨¤—”hQ;CWîyQšç/Ö ß^(pö¨ËÑ•ceNÝ®éq”¯˜–Ç("o†u”D‰\¸{P¦Òܾ8½€yž! Ý\M Chœ}UÄt ( Ulèѵ¦…‰ën·a ¼iÌqÌØÜê;Ð"l“]=‹ ±ºž´Q9(Bœ¼â‚ôpG(""a€ @r "\ÁnÊQø¡Œ¤JA± "‰t)•nŠ–‚  ’ Ö¤1¨ðZE¼¬%¢+”Bë¡ZŠ’*¸Àp @(!h.PBЮU¥ø\‰XV,Zˆ‘F%Ì8Æ" È‚ÄDZ"ÔDï¯iTã•L©’øªQÈ‚9 Pƒ!$ &V”rŠ€± ˜Á âRQñˆ«û·--²”g—,ãW„'{ìŲ́wˆÞbØk#2V_ž°mº5ˆ;C/yÀÃ{È–åææË¨ˆ¸U¯Ž–VÞ{ºixu}2"S’ô·=Bò¨Ó ˆÛ.Êă±fšJ¶½áL¹s¼b&6GŘõÉ´•ÐÅœYØêxø#È{9Ë›í€âö)£ES€h]‰BÁºG[[Ùè&}oíŠì-M7VšW‘jéÞTÙF­­F¾®i`Îd”†Œëx0QEˆ!ô²£¼á¥æ+ ÜÝ=ðçé%ØýÚMk•ñ¨s„Ýdñ ½ù$ظ„/””3Ø”-g³ŽˆøÓãßÞr*Q¢Fº‘íæ>¡r¬" ߆Ö8“ ‹ÚDw‘ª|Ù˰[R©9ž«¥™mÄŒ—â2ÙŸ+Vð™±ZA(xcœHÛ/=óŸ\}õÏxXiR–3¬Š÷Aüª "þpE †Žiæxu¨7;ʤ÷¼òȆ!ÁѳÄ!pÅŠ NÇ*ÔzŽ*³Þ‡Û¨½ YÙÊÁ!{¡D Æ41_ ÷2¬=$xÎÚ9‘ê¡9ÏÌ'1™öS}~ú½Ÿ;.?ƒI˜£ç®¶hªÐ=ò¯fG?%>gÉÍ~Qñ¤“ùM4ÐÊØøcÁ‘“l¹šEv€y}ŒÝÎÄÜYp ›ãA£zIÖk˜±õìòݽ‘K†XÞ,îuK¸‚Ë=w½–±®uZ¦‡Æ”V㬴&‡¶ÍÑLêÒiõ»Ì[m¢ G[·B•¾46&œÝ1Rf•˲ nÞvíÆÉSk qQ^GÞ½ÈÁv·¬(c¢êM‘ƒvD Å–ÍÇ—;³rg/r’1hÒZ,Ûe™aª¨]¾áÅC„çv5£†öÕs¦ÊÌL3ŽlŠ*Ú×HΈÖH$Fdiw’ó7žÕï[nÄ™kSî«¥žêkÄÆŽä0¶ÝbIE`Pç!²uRˆÈ)&á´Š*ÙùÏÒ§c-cñéõGᧇ×Buö½ ¿¤•Ã1räÎÏGðwí´D`éâûé¸ÓMføu=¸Ësô¬(À-Öþüª*ïï%k…ø8E¨øŸ’ìýúø~4?Â?Ãêw…Ù«Á”ÙbƒÆ~“YCæ…ž“îõתS«IÇô~7×ÇÛH>‘)4ñØgaÖ ª‹%auQoïgȬý†dsgåLÔÍ»º A¿0ÔVüGÅGãÌßÎ<‚߉&TÉ[¾™£)›ù1˜Â±»„8Ÿ *wõuü½ySw*òvìß»ÔdïX‘G„}LâË´¶°À„}úøêU>áA†32%Ƶô’!£±” G6T™^üN‚8\DPpƇ…—(‘øãtdmr~£C"‘÷#ä83œ£ñƒ# ÔH?ÝûL ͒Ɉ;—€¯ŽÀêÏÒÈÞ¹ƒT}ò™Ñ9é Gâ¯zž%õ«²^e,s‹+qb‘±Q÷CD ò*zRRœÎW·í(A7E”R9Ç×!h¥ ”AjöËs"D4R=î$›É ïOH2-~&AcHJÞëÑLÔÉg¶TÄ$$#ô‘ m'% J!ì¢AˆJƒŸ¿*ƒ ”‡òb@P†!xQ"¬üi¥áF_ïœö~=~DZƒêd~Ñ_›rP‘”Ã=4MäÈ™j |Ù”‚ÑÝED\_B1”—*’³J1¡yW5(²„ó! üxe”„† ŒGã»õÏÌ9[€h'ÈùûiÓÈ%D$£¡å²)Õ!ˆ 0¦HᆸeþsIü0£>?3ê4“Qß“>>e4˜ZÌ$C¦6ÃÅVþü;÷½ã 6$ÆÏC¢b+pYs. (dM²‰uüð^#„IŒ)G~øÍ?.#Dƒ(ÞEµßÇoñ•iÝp¯Ïzž÷–w¯&èÞž> .Э‘† ®õz÷&ªQãÃ8ˆ‘¥Ý‘gá±…þõP1ŽD4GÍÁB m·%˜„ƒðˆ0ó-Ü"°YŒ°b+Ò|oàÒ$Ü.€ý{eç¼&G øüt„#aÁ(¾g"&<ÏOhˆìørRv~Ë«ïzÈUž£!â³ Ïs˜GñtLÏíTEV(.]¯˜K7~¾“BÐH¾fšÈg†r!XÈò"Ñ¡¤¨gÂGÇXäRÆ›ŽD_ß< >FüT¾ñ$£QK8Æ,¹ŒAˆB"žÂìŒPts- áhƒ}ôá2õâ°œæZ<(‰í©Ç.fÉ0GàQˆ­—ªÓüýV[ò 9ÁËò(—[ïÒNߨ²fíçΤµÓ›E;ßHש;¬0í/ðC?být ?3ÎK³îEÕ™†Îï´U¢?5|,)݆èÊãL¢Ù„ž®÷ =Æœd# ´V£FH¥“ëoïXr ”d"óæÆßÔ|†…dV1yŠYÈt*WpEš„‰„E>3$,Ær"y†âôú 2#±I âÕÏÞíò¼SGmÝefö£©WUj¥ºg° ¦-  :\±ƒMgÚâ5r ;×B9“b1ÒyHÛ!öI€Œœ( ä|H_¥HÑEÛ¾m3ã²ÎùÄü¼J“xae˜ä>G¤UtVb~Û ñ¬eÑDýe‰‘§HD #Ìg‘ó‰Ò1’sûPÉ>>¿ Ö¾û·(¹‡1Õ:ÚÑØ¬ªËŠªâjnõ.Ä32­¼Ä/N½}†ËW][•4v«œ]ìËž]ÜçmTo¢eTîÞ¦"2øv 9’ùnÖ°ÅšQf RJèwSy_rÛ‘Ôó5¬P¶»VEÕžMW&ot91Ì.Õš†MíÝyUì]Ø)¦Õní\⽬5㜙ÎÚÞÄ4<îwE)ð»íÜ»<;6‰i\š©ªò·|Mж,¨2ÂHvecq·†³#W&míÍ—ud8¤xTÒˆ³÷ªìòG«c• h”Ö_Æ}iXÌ¿™­{Š"3æ#œ´Ú]@yˆ/ÆÉ¿Œ¨ø\ŒÆq;'‘äR*™Äóê§Š&Çåï¯ |c¡E ë’f”†NÍ æI,³ID²gd~ú@urZ Fš†!Sg̸EÕ’R†e•PÊÊ£‹?0(œ‚öI"„¢Í¦yo:œu6Æ+NŸ½(ë-gÚ7fK3ï}&“YCfÌJ'Ì×Q".nuyÞ˜† ò9|4ï1’,QÃµÙÆUÃXqE@±…K)/SqGÚ G˜Ê„DÄOfYöžÂ¶lñ`ÆÈ-x/æP¢(—ñób».„{5Ø®¦¯¼LúM&ŒÎü'HOo¬“¹”˜$A7oMÛð Õ¼DC‘ 6¦³/%™SdÑWCéÏfA²³ç×TFÝΉ­3ѧµO+ä‹E] .lwÀqg£¬ä!r–æôJJÜ–.*vâÜŸ‹8ŸZ“©pèäu³(Ÿ®ŸÖáòñÀë°´3Æ)âÝDtîÕ·dÌÄéöü× ×¹Ú2x˜jîÜ"È91'éR”¹¡Œ¯˜çSk±ª²Ç—sälœ{)º7¨'7²‰YñÅÑñö“÷Š(üK:±LìŸ\ÇÙúJsÅ~'g ›kÜäWg$~٩ί¢‡ÔùÏÁc¶‡AB”˜bÉŽ³„Z°¢zîs¹»+’sqhîž4D"hGÞ1(`Ð!°U ëf®ëœ…¬5Y÷c•Éõ|\3Ãm¸oÉH}ƒ)4¡N)Å»Œh^ÎNÊ•¸?§Å`(ø[·&¿º„·šE”&Åî¢}á_‹Ešh¢Ó„|©‰z¾^™Ti±Q ¯+¶yžŠóìC+Dx#hNœ]FÇŽ‚è0Æ`À=ÜÔÙèÁ6Ì8üþf%”jýã ™g×uAeÕwÒ»å c£HëOJAƒ¡ ëZKÜ+ƒíq™ìžT\7ê’O¾¥‹N¬? ™fÇÊÞD¤g ¶ÚsBñ7d’èOMÙ_*÷F?vä7V:¡ŠÄ‘'ZÙʨÁ%ÐÂõyû; :>ÄÎt³,˜1Aš¯Œ³Ñ\,®+cèÈíìbrÒh(X©°;-Φw‡·R1Ž3¾. òhõåñ¾nðæuTO 9eIÒhI€N3¬‹Ë~ΊVVOèZïAW[~z¤î÷¹‹rájU6e¸¬¤»Våº%| uåd¶¶Üý°äÆ™!d$Ež/ŽÝÐ #"qäsÆ3®b$,²Ú?1ó'4ŽæušÌJ»Fâ ø2fÝÙ†z Fã:Ûsã¼&ñ ’üxe~Âã~‘Ȇ‘§ß“+ì¯ßtÎbØM°ìîËP»³›“Ü!îÊMr¡UФ£ÎðsœW’“ô~"W…b„Ìø“?"˜»ñ%ˆ¦™^¢Mª/‘îÓåõ¹.äjµ~ݦi«‡)$ék{{Eh‰DÑ?Ç/ÞܰXY·ð™F†²Mi‰ùG`«søþ+nýÛƒÁKù„-Êêåѵ@h;ÖP‡RnÈ)sº°Þ½Ì¡»‘ä烿½q¿±¡*õ ï”éì–$FĨaeQù>{t•èÌ0a÷ŒíIÍ—Ž ØÕ¡Ó¸:=‰3)Kc™NpŠ(—zHo™„ÑkÞLYaˆu¨¼'F?o™Û¶Ø¼)^®)Ì¿|‡8ψ$>«=XË ÆW»s ¶tjèSÖ2Ãnu¦2#fëXûf^1v]~S$$çWijŸJ]¦°žáÓj^e‚AÌ+ŠŽ÷Û¹*» ¤ÊEJ™«½Y|)]9@8ë–m!Ê/rŸ`ºR++o•ÒŠv0Ušuê0ª=&j0¹£— `["]‰ím$ Çkp8´:Bb‘å0ÖWÈZ‡VoBCaì ˆ · ÞÖ“MKqJÊ‘éãůžÇ14¦j0vµv‡z„ &Î2xÆ€cYDültOsQ¢!àÄ;ìwPûXâ&3Ç3<£¼HöÌCçÓ=–=¶Qˆ_²œŽ‚1©$߈2K3ÊC]eP—c`¡hPOÁƒŽù½g‡9Ç ã`Ùí{\œ]†Œì€x¤7ÈæU'1&³™Á>ÃJ‰Tažö“v\{Eš™rHga%i‹z0âKד{86“­C„‰¨“ÆQë4y ›n‚Pð“jÖJ’g1½ÕïUf@ÎVW,ÛéDž˜²Íf¾K¯#Qǯ²ÏE0CÆO³ ƒ“˵À\wa² ™¶åàÚK6ãÁVUÈÀDìGàáÉ_’A ï¤Ü‘7¥£ElYG…—l `Úˆ±öîqrйWGÕä:jÓU*Yfž¤)Ôæ’th…’±@†Œ‡èÍ|O¼ÕÌ_¸Ã ŒâÁã Ä#Õ’{ÝÏ*Ë/|É0äqÎph¥XfL¹ºÝÇ)»DäÕ4O £ÓtPQé÷ðž–{¶O¾Ñªç…¦Ü”÷YgÄdûнÛͯ̕žÒ½+'.Ò[°ÎÐÚ¸¤ˆ©¶ &í¶*úè%ÚN°åŠÖôòÛG÷1õ¹3GÕ; cFÚ¹tq91B%]­ÆLP˳O-ue3gÖ>j«WbU¼&l¹¶+3j> Fój2{€î;7KÎ.ñËØïÕMA×^•‡®uU>²ùˆ8æµø‡¼ØégÆ]”2º\1qÚz2Û‰8 Û¢ö¦ÓMЙÙÓ+No,´Væä—Sé:ïCÜ…§pæ¶–Z_úçouÏ¥º”„mí ŸXÁ×Cl fÞ‹@ñ»Ã źæU`îSoÕd‡@# +nÒ¶æÊ;®UjAˆsàùaŽV¢Íf!¾–1ŒC½—g‡Ò7»ŠÚA:ì8z ®8·UÊ—>öWYR´Þ:¹”i¢bÕ<åTŠ$Ü­/"Žñ|©8ÙÍy”R$œ“nË Úpç’è^±žÃ{ªJ‡æ´õt.ìÂÊ£uݦ ­Š½m"_Hµ‘&ÝíÙ6ô¹^PPû™´ìb++¤öK:ˆëÃæ{8Âa—®:ݦ,YU8éöög8gq·«^ºaÔEb´ë=¶ý ‘‚”,$XH0W–ðÜÃ) NÄp4À®ÛÐ03c{¼è`l~Xõ{}Î_S8w3̨³ÃÊñÌÇDÉ܎˰.’‘Àn[mζ²à·V§gw5F—N š{°5F¦6èWU03ZVÌΖ{ÝI$´‘Ñ!2½}½Ûg£|Sò3f”mÛÇYr𯉓“úeN Mu{oH/˜:ä:Û'fUJ& Vö§³|:–uáYìê¾µ®‹òØíu÷$âr;-,¬ƒVÐ63=$–ÇémvP¦gdb‰ÁˆQïdùB›ªàñÅψ˜µœŸ™Ü7–[ç4¥IQªÊ«O­?g0XHôs5œ6Þ Ò¢£.aŽ+9‰­HàÓ ‘{ä¬öD­±wȨe*¨´“´: Þ:4‚` ëÛ›¬ûJÚ‚Å£.)•÷¦\¢¨»IŽY­)¢ærX ëK ¢‰<€Ë¯RŸ:&ÓœŸ ¼XÉÙR¥pÅYdL#”Z|æ,æcWËrк°Î Vv<£–08¥bæX™4™9&ñ©žcJóF-Ø;ªÙTOe(éõH¨U¸º738^Á%[tdÜÆvãy bÁö›ö9YDª#';;”3#L‹E·–V:›°DÅ(Ó°`D¦•;éÝW×aá$àŽ…Úáð‡º1»]z³,f5wÔ[>Ҝ±]IEª”‘|w_…Be{Öe'TÍÝ–±\Ö‡cP¼¦…¼¹MT_±“s­ªöø·ã¤ôÊJ$¬<¨¡0›MIêmçS:¶^Ê´˜¥úò½ÓkqxÁÆpä3zúÑ8„j »y°‹ŒPX{Øë{ˆ¾3¸Ð›‘–@„xË5Ï9âðWg nˆJ)Š51Q6Ë›¼§6K>/½L4ª-MRTŠê2fÛj–¡`“»…[Ñrô] PÄÅòë t²2æ0q”VS‘Ç@’êÇ9)Š6Gáч…ÛÝS3^¶wGè ÷´SÔœ/«»ÎuP^›Ÿ<Á'–ݲßKø’Á2ž»ê­ñs(x2kJIQŽI…®û®e”%‡’§6f}ìŠ5¹ò¢Jcݳ4µ§©Áf©ð„Uv{ØÇ—D.f˜±šC;ᢅ²0ué¸E+ì<ÌÅÛB˜²¨§t3ëMö•+È]ÓW¢ºt{Ø ‹¸Uc ¸®âaæï†ìÈ¥gPM±²–߯5©SQ¢à(Ô&CÓ´ÍR‚A…Œ%n‘Œ HéCƒ ©û-ö%X¬Ž\Ò25ãUSº~”0êÈTJŽÎ\édcÅm3žÊ1Fõ¥Vj÷=àƒ½R)ìsØ>/IB¹ØFŽÄEtFP(VD+ñpÙŠŒŽô¤¥ B8NÄå4mm¹£­fÓ—.©äòH÷…` ÕŽ1û1–ŸFÙ2¨cfW#Ã9·=è~6[Îà©¾í ¸ ÔõäfPéÜw¤­ë‰ ’oÊýÄ’aáb36½â»Ž(»s¦âºK{DÃ¥ÊÛ¥gr§‹[ ´`†™5¸±ÈÖHaVapaʉ‡Ép†Ü¤T]è¨Â“¦gƒjŠšb5^SNqA4æ½Ruo{¼–÷žÄܼ“ÄÇ[0@€÷_>l"†yk«¶á–5çmgyÇGw×N0ãAçr×G %%‚*À´†Ì0¤-Á/F A•2°¹mò&…ÑpY½§JÜÚÅ7Œ¬–ŸA[Öó&¦ƒÜ¸3”-½±¯&$¿kº %hŸ7’‹^Ûw¢éEa(x{qÙ}ˆ)³8åîeVa•„ÃXNHiUO).Öô¶g¼DÁÃZØì$hÉ`%ØÖtó}-qhnKTÎ[ÙW]Cpo-¼¦î- ӋÖf9­#H)HT^¾b«´¥§«T¥r mÍ—K^™»TØT¡ei‹ƒQ¡wy]ÍÕ¼«;18”ÓY¦¬óӖݳL°TšÙQA^Ü>@C*5©.]È"Ô–øQ ra›iëlg+Ï`™ ©Áp:;_eUª”uÕêN¹U’àa9‡FñæâÙ ¼ŠƒÌt$Q½xR¼3s‘9"Ò ÉM>äãŠÊ?È8PD@oÒ“ü¸ýûìÞíœîU¯°’{ñÜ8ðz°"]êÓpm3ÊyP}pç¥.Ù2£„åWö*dÕGFŒ¾ÐÅ ©aQhäTmEMºç|ðÓÔHGš½7¸ÕE²Cƒˆ)Sª³P!„* ”á9F§¶P¬"' íG°dîJ¦wM=”bÍÓ•8æ1…:ÁX› ¹cg´/a¡F†6õh°¹‚l:5G<©E,†\ÚJ$²v;`ø PÞÌú•;/.B šÑDhèјȨK+a©Úí8؇yhµN æ%SˆÛ2“­‹„|LòD­3ÆݱN¹9ž=’vB¬ãi;â’ëÞì4õò$†t ß:-Œ),¦00Uè½0³;®ò×!Ý $¼ô}°šLF’vÌY®cS6ÍZ•‰Bòa+GppïNi*¶ÛƒÁ ™ÞÁfÕŽ¢'’ ⡼0±6¨œ[y¡yáŒÃlSÓÄ¢´D×±>’ãîñÝ«n­6åL±@ÖmRlX§T%Ød_lÅ ¶û;Öô=)sÌ•`ù{ÉS=ÄǬÃY“<Ï<(ÐÓÜ»åØpƒm—¦¸vPÊèê†vF0•íîÛLG¤Dü) ¯sÆ}i¨LE;÷9Ì3Ø¥ŒPç $q™@wÅ€ ««™w‡j‚}÷›’á×I^fÛÑMÑÎÍcá¶Í£°¡‹:Ò~*Ö.ç,ÁÔ|!l¾¶Ûî,Á% ­ /w!%õJχƒ&>*ˆò û>É Ìß?P³²]þðŠ =#óã!‘b÷´“hf)9TÅØÍDj@‰#˜! ´4uôöÂqMF$g¡WM ½ßdãu:%9bvŽ×i ûÜC> Ç«A ãí¤ýì”qÌ>PZ¤—Ô’â{(G8kÙçg‰6Mñ3‘O¼”˜(“hê%H˜…¢sæm»TzßÈ¢×Ü´™ž$´eL lé\0“ç‰Õ ¾Ò⑆r¯¼w?ܨb4ÛÌ}éK²µ^ù§‰­Ú•‡1[ùW.õ_;dGÚAçv?…P|ºÙ÷ɈøGÊela†à}ÄòŸG&Ž*"…/½­›;cç­>ÅÅÃ%Z=Ä!(&´Œ³31ªŸiDEï/ŠÈžVkO±8Sè’/ wŽE2{‰a—ñ?…Ç•DÝ–Þ(¡g*2nK÷–ý‘íÆÍ"[ìÈ(—İR‰S(”DÞuqhïL Dôæê`–#’g–ϽZQ\þcùÜL±YC²aˆ[Ìœ.ÃjðP²AûfØ4†>|Qõ¶À=Ag v·GÕuó\¶ÎwÝi µvo‰8‰É8¤ƒ·L}â- Pøöu q–ØÚµ¸Ÿ®ÄÐÙ4¥'½w˜Ã>Í}ßmýÏ/÷QlÈô0™›2^åfù½„ ú¥Å·ŒB¯>4PRÉQa_ 2z»æuà¸õ<àï˜ü2€ëL˜#¹I°T( ”*R¥Tåñ«ouX BZÖ€@€B€@ @ @€  B!@ˆ‚€ªµˆ ­Jª’KŠª•$‹— J©Ä!Lä•*¤‘k•*d‚¤T’1")•YìDRˆ E#T ú\ ‡$@I @‘P‘’FE‘$‘dPd$QP$I$dA‘Id€*¡J•%ª¢*‰|T¤ DW¬ˆ…Ý?séôûÙwÞÿ¿\ÑN¾v·Yï÷çÝÅõ¯2…QJ<·9Òçà"ƒ©ã")Ýï[¢zü¼¿GڽɚTRlŠòDRšDX\ŠtQMU­â†ÏT²"€B¨¥õªž@1¶Žàf*Z ½JS6ãS„ð88ô` Zëè ("”n¢©C!E® BÆÊ`¢•›8TÕ'ÔЪ\uaÔˆÆ PRNú)Ž$"!! ¹eHŠT×H*¢\QØàŠkÛce⧦]àE=JæŠ`Š]ˆ©ÅÈŠpí-üMȧ¤ŠmE7UT,MT¨‚:u"™õMxó‘N4Rp×S™1›‘IÒé¦Ý…´  Æÿ Šœˆ¦ƒ* œó}‡&7¢›EMZ ±7îÞ¶³|Ar"¤¶bn‚†:4T¿mNDS‡£ @0Ó1›…Nz)¬¦¡SE†íëQÍËes¦H¦b¦H,:â¦å»…ÀÐã¶€*DS‰§ \ÀôSJ©y½uJ7(ýbåË¥ÉVäE݇)ˆ©Òš‚ ŠØE:ú"”E5ðkÉTÜŠQáE1E:j¦÷)²è^r¢”-©Ëèg[eDRøXTœh¥½K"™òŠ€†ÍDSnßEÒŠnÐ(`d*PÔÜŠXßT,ªCw>ÿ¥ÀŠPµÏ)ŽlÞu¢”/3Åðâ*tKí]ºsE1P Ý{h‚8ÜŠq"Aã3E)­Ë%½碘šøEJé9ȤÚÄC#^<( jE.ч;1p/E9jolE5"›•޶ÑÞÒ*m%QMµU)¹Ïý€¢âæy€käýq|õ~{§ÅÍûdË66æòKˆB~_=>:Xóåú>ŒK¿¾½iÞ<>{%¸1¥@Èÿ•ôzž>æÇÍçÀ ²xÀèˆP,óx˜ùþ™žCüá–‡˜ñ˜l<Ÿ4¡^oJž]x«ç¯ù^¹ôsÍü?‡ñßEÿ!w$S… ÓÆâ osmium-tool-1.7.1/fix-formatting.sh000077500000000000000000000002241315004223400172710ustar00rootroot00000000000000#!/bin/sh # # fix-formatting # exec astyle --style=java --indent-namespaces --indent-switches --pad-header --lineend=linux --suffix=none src/*pp osmium-tool-1.7.1/include/000077500000000000000000000000001315004223400154215ustar00rootroot00000000000000osmium-tool-1.7.1/include/rapidjson/000077500000000000000000000000001315004223400174125ustar00rootroot00000000000000osmium-tool-1.7.1/include/rapidjson/allocators.h000066400000000000000000000241071315004223400217320ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ALLOCATORS_H_ #define RAPIDJSON_ALLOCATORS_H_ #include "rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Allocator /*! \class rapidjson::Allocator \brief Concept for allocating, resizing and freeing memory block. Note that Malloc() and Realloc() are non-static but Free() is static. So if an allocator need to support Free(), it needs to put its pointer in the header of memory block. \code concept Allocator { static const bool kNeedFree; //!< Whether this allocator needs to call Free(). // Allocate a memory block. // \param size of the memory block in bytes. // \returns pointer to the memory block. void* Malloc(size_t size); // Resize a memory block. // \param originalPtr The pointer to current memory block. Null pointer is permitted. // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) // \param newSize the new size in bytes. void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); // Free a memory block. // \param pointer to the memory block. Null pointer is permitted. static void Free(void *ptr); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // CrtAllocator //! C-runtime library allocator. /*! This class is just wrapper for standard C library memory routines. \note implements Allocator concept */ class CrtAllocator { public: static const bool kNeedFree = true; void* Malloc(size_t size) { if (size) // behavior of malloc(0) is implementation defined. return std::malloc(size); else return NULL; // standardize to returning NULL. } void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; if (newSize == 0) { std::free(originalPtr); return NULL; } return std::realloc(originalPtr, newSize); } static void Free(void *ptr) { std::free(ptr); } }; /////////////////////////////////////////////////////////////////////////////// // MemoryPoolAllocator //! Default memory allocator used by the parser and DOM. /*! This allocator allocate memory blocks from pre-allocated memory chunks. It does not free memory blocks. And Realloc() only allocate new memory. The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. User may also supply a buffer as the first chunk. If the user-buffer is full then additional chunks are allocated by BaseAllocator. The user-buffer is not deallocated by this allocator. \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. \note implements Allocator concept */ template class MemoryPoolAllocator { public: static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) //! Constructor with chunkSize. /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param baseAllocator The allocator for allocating memory chunks. */ MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) { } //! Constructor with user-supplied buffer. /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. The user buffer will not be deallocated when this allocator is destructed. \param buffer User supplied buffer. \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param baseAllocator The allocator for allocating memory chunks. */ MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) { RAPIDJSON_ASSERT(buffer != 0); RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); chunkHead_ = reinterpret_cast(buffer); chunkHead_->capacity = size - sizeof(ChunkHeader); chunkHead_->size = 0; chunkHead_->next = 0; } //! Destructor. /*! This deallocates all memory chunks, excluding the user-supplied buffer. */ ~MemoryPoolAllocator() { Clear(); RAPIDJSON_DELETE(ownBaseAllocator_); } //! Deallocates all memory chunks, excluding the user-supplied buffer. void Clear() { while (chunkHead_ && chunkHead_ != userBuffer_) { ChunkHeader* next = chunkHead_->next; baseAllocator_->Free(chunkHead_); chunkHead_ = next; } if (chunkHead_ && chunkHead_ == userBuffer_) chunkHead_->size = 0; // Clear user buffer } //! Computes the total capacity of allocated memory chunks. /*! \return total capacity in bytes. */ size_t Capacity() const { size_t capacity = 0; for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) capacity += c->capacity; return capacity; } //! Computes the memory blocks allocated. /*! \return total used bytes. */ size_t Size() const { size_t size = 0; for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) size += c->size; return size; } //! Allocates a memory block. (concept Allocator) void* Malloc(size_t size) { if (!size) return NULL; size = RAPIDJSON_ALIGN(size); if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) return NULL; void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; chunkHead_->size += size; return buffer; } //! Resizes a memory block (concept Allocator) void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { if (originalPtr == 0) return Malloc(newSize); if (newSize == 0) return NULL; originalSize = RAPIDJSON_ALIGN(originalSize); newSize = RAPIDJSON_ALIGN(newSize); // Do not shrink if new size is smaller than original if (originalSize >= newSize) return originalPtr; // Simply expand it if it is the last allocation and there is sufficient space if (originalPtr == reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { size_t increment = static_cast(newSize - originalSize); if (chunkHead_->size + increment <= chunkHead_->capacity) { chunkHead_->size += increment; return originalPtr; } } // Realloc process: allocate and copy memory, do not free original buffer. if (void* newBuffer = Malloc(newSize)) { if (originalSize) std::memcpy(newBuffer, originalPtr, originalSize); return newBuffer; } else return NULL; } //! Frees a memory block (concept Allocator) static void Free(void *ptr) { (void)ptr; } // Do nothing private: //! Copy constructor is not permitted. MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; //! Copy assignment operator is not permitted. MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; //! Creates a new chunk. /*! \param capacity Capacity of the chunk in bytes. \return true if success. */ bool AddChunk(size_t capacity) { if (!baseAllocator_) ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); if (ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { chunk->capacity = capacity; chunk->size = 0; chunk->next = chunkHead_; chunkHead_ = chunk; return true; } else return false; } static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. //! Chunk header for perpending to each chunk. /*! Chunks are stored as a singly linked list. */ struct ChunkHeader { size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). size_t size; //!< Current size of allocated memory in bytes. ChunkHeader *next; //!< Next chunk in the linked list. }; ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. void *userBuffer_; //!< User supplied buffer. BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. }; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ENCODINGS_H_ osmium-tool-1.7.1/include/rapidjson/document.h000066400000000000000000003362021315004223400214070ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_DOCUMENT_H_ #define RAPIDJSON_DOCUMENT_H_ /*! \file document.h */ #include "reader.h" #include "internal/meta.h" #include "internal/strfunc.h" #include "memorystream.h" #include "encodedstream.h" #include // placement new #include RAPIDJSON_DIAG_PUSH #ifdef _MSC_VER RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data #endif #ifdef __clang__ RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(c++98-compat) #endif #ifdef __GNUC__ RAPIDJSON_DIAG_OFF(effc++) #if __GNUC__ >= 6 RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions #endif #endif // __GNUC__ #ifndef RAPIDJSON_NOMEMBERITERATORCLASS #include // std::iterator, std::random_access_iterator_tag #endif #if RAPIDJSON_HAS_CXX11_RVALUE_REFS #include // std::move #endif RAPIDJSON_NAMESPACE_BEGIN // Forward declaration. template class GenericValue; template class GenericDocument; //! Name-value pair in a JSON object value. /*! This class was internal to GenericValue. It used to be a inner struct. But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. https://code.google.com/p/rapidjson/issues/detail?id=64 */ template struct GenericMember { GenericValue name; //!< name of member (must be a string) GenericValue value; //!< value of member. }; /////////////////////////////////////////////////////////////////////////////// // GenericMemberIterator #ifndef RAPIDJSON_NOMEMBERITERATORCLASS //! (Constant) member iterator for a JSON object value /*! \tparam Const Is this a constant iterator? \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) \tparam Allocator Allocator type for allocating memory of object, array and string. This class implements a Random Access Iterator for GenericMember elements of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. \note This iterator implementation is mainly intended to avoid implicit conversions from iterator values to \c NULL, e.g. from GenericValue::FindMember. \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a pointer-based implementation, if your platform doesn't provide the C++ header. \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator */ template class GenericMemberIterator : public std::iterator >::Type> { friend class GenericValue; template friend class GenericMemberIterator; typedef GenericMember PlainType; typedef typename internal::MaybeAddConst::Type ValueType; typedef std::iterator BaseType; public: //! Iterator type itself typedef GenericMemberIterator Iterator; //! Constant iterator type typedef GenericMemberIterator ConstIterator; //! Non-constant iterator type typedef GenericMemberIterator NonConstIterator; //! Pointer to (const) GenericMember typedef typename BaseType::pointer Pointer; //! Reference to (const) GenericMember typedef typename BaseType::reference Reference; //! Signed integer type (e.g. \c ptrdiff_t) typedef typename BaseType::difference_type DifferenceType; //! Default constructor (singular value) /*! Creates an iterator pointing to no element. \note All operations, except for comparisons, are undefined on such values. */ GenericMemberIterator() : ptr_() {} //! Iterator conversions to more const /*! \param it (Non-const) iterator to copy from Allows the creation of an iterator from another GenericMemberIterator that is "less const". Especially, creating a non-constant iterator from a constant iterator are disabled: \li const -> non-const (not ok) \li const -> const (ok) \li non-const -> const (ok) \li non-const -> non-const (ok) \note If the \c Const template parameter is already \c false, this constructor effectively defines a regular copy-constructor. Otherwise, the copy constructor is implicitly defined. */ GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; } //! @name stepping //@{ Iterator& operator++(){ ++ptr_; return *this; } Iterator& operator--(){ --ptr_; return *this; } Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } //@} //! @name increment/decrement //@{ Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } //@} //! @name relations //@{ bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; } bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; } bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; } bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; } bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; } bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; } //@} //! @name dereference //@{ Reference operator*() const { return *ptr_; } Pointer operator->() const { return ptr_; } Reference operator[](DifferenceType n) const { return ptr_[n]; } //@} //! Distance DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; } private: //! Internal constructor from plain pointer explicit GenericMemberIterator(Pointer p) : ptr_(p) {} Pointer ptr_; //!< raw pointer }; #else // RAPIDJSON_NOMEMBERITERATORCLASS // class-based member iterator implementation disabled, use plain pointers template struct GenericMemberIterator; //! non-const GenericMemberIterator template struct GenericMemberIterator { //! use plain pointer as iterator type typedef GenericMember* Iterator; }; //! const GenericMemberIterator template struct GenericMemberIterator { //! use plain const pointer as iterator type typedef const GenericMember* Iterator; }; #endif // RAPIDJSON_NOMEMBERITERATORCLASS /////////////////////////////////////////////////////////////////////////////// // GenericStringRef //! Reference to a constant string (not taking a copy) /*! \tparam CharType character type of the string This helper class is used to automatically infer constant string references for string literals, especially from \c const \b (!) character arrays. The main use is for creating JSON string values without copying the source string via an \ref Allocator. This requires that the referenced string pointers have a sufficient lifetime, which exceeds the lifetime of the associated GenericValue. \b Example \code Value v("foo"); // ok, no need to copy & calculate length const char foo[] = "foo"; v.SetString(foo); // ok const char* bar = foo; // Value x(bar); // not ok, can't rely on bar's lifetime Value x(StringRef(bar)); // lifetime explicitly guaranteed by user Value y(StringRef(bar, 3)); // ok, explicitly pass length \endcode \see StringRef, GenericValue::SetString */ template struct GenericStringRef { typedef CharType Ch; //!< character type of the string //! Create string reference from \c const character array #ifndef __clang__ // -Wdocumentation /*! This constructor implicitly creates a constant string reference from a \c const character array. It has better performance than \ref StringRef(const CharType*) by inferring the string \ref length from the array length, and also supports strings containing null characters. \tparam N length of the string, automatically inferred \param str Constant character array, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \post \ref s == str \note Constant complexity. \note There is a hidden, private overload to disallow references to non-const character arrays to be created via this constructor. By this, e.g. function-scope arrays used to be filled via \c snprintf are excluded from consideration. In such cases, the referenced string should be \b copied to the GenericValue instead. */ #endif template GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT : s(str), length(N-1) {} //! Explicitly create string reference from \c const character pointer #ifndef __clang__ // -Wdocumentation /*! This constructor can be used to \b explicitly create a reference to a constant string pointer. \see StringRef(const CharType*) \param str Constant character pointer, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \post \ref s == str \note There is a hidden, private overload to disallow references to non-const character arrays to be created via this constructor. By this, e.g. function-scope arrays used to be filled via \c snprintf are excluded from consideration. In such cases, the referenced string should be \b copied to the GenericValue instead. */ #endif explicit GenericStringRef(const CharType* str) : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); } //! Create constant string reference from pointer and length #ifndef __clang__ // -Wdocumentation /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \param len length of the string, excluding the trailing NULL terminator \post \ref s == str && \ref length == len \note Constant complexity. */ #endif GenericStringRef(const CharType* str, SizeType len) : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); } GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} GenericStringRef& operator=(const GenericStringRef& rhs) { s = rhs.s; length = rhs.length; } //! implicit conversion to plain CharType pointer operator const Ch *() const { return s; } const Ch* const s; //!< plain CharType pointer const SizeType length; //!< length of the string (excluding the trailing NULL terminator) private: //! Disallow construction from non-const array template GenericStringRef(CharType (&str)[N]) /* = delete */; }; //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function can be used to avoid copying a character string to be referenced as a value in a JSON GenericValue object, if the string's lifetime is known to be valid long enough. \tparam CharType Character type of the string \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \return GenericStringRef string reference object \relatesalso GenericStringRef \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember */ template inline GenericStringRef StringRef(const CharType* str) { return GenericStringRef(str, internal::StrLen(str)); } //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function can be used to avoid copying a character string to be referenced as a value in a JSON GenericValue object, if the string's lifetime is known to be valid long enough. This version has better performance with supplied length, and also supports string containing null characters. \tparam CharType character type of the string \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \param length The length of source string. \return GenericStringRef string reference object \relatesalso GenericStringRef */ template inline GenericStringRef StringRef(const CharType* str, size_t length) { return GenericStringRef(str, SizeType(length)); } #if RAPIDJSON_HAS_STDSTRING //! Mark a string object as constant string /*! Mark a string object (e.g. \c std::string) as a "string literal". This function can be used to avoid copying a string to be referenced as a value in a JSON GenericValue object, if the string's lifetime is known to be valid long enough. \tparam CharType character type of the string \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \return GenericStringRef string reference object \relatesalso GenericStringRef \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ template inline GenericStringRef StringRef(const std::basic_string& str) { return GenericStringRef(str.data(), SizeType(str.size())); } #endif /////////////////////////////////////////////////////////////////////////////// // GenericValue type traits namespace internal { template struct IsGenericValueImpl : FalseType {}; // select candidates according to nested encoding and allocator types template struct IsGenericValueImpl::Type, typename Void::Type> : IsBaseOf, T>::Type {}; // helper to match arbitrary GenericValue instantiations, including derived classes template struct IsGenericValue : IsGenericValueImpl::Type {}; } // namespace internal /////////////////////////////////////////////////////////////////////////////// // TypeHelper namespace internal { template struct TypeHelper {}; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsBool(); } static bool Get(const ValueType& v) { return v.GetBool(); } static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } }; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsInt(); } static int Get(const ValueType& v) { return v.GetInt(); } static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } }; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsUint(); } static unsigned Get(const ValueType& v) { return v.GetUint(); } static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } }; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsInt64(); } static int64_t Get(const ValueType& v) { return v.GetInt64(); } static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } }; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsUint64(); } static uint64_t Get(const ValueType& v) { return v.GetUint64(); } static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } }; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsDouble(); } static double Get(const ValueType& v) { return v.GetDouble(); } static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } }; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsFloat(); } static float Get(const ValueType& v) { return v.GetFloat(); } static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } }; template struct TypeHelper { typedef const typename ValueType::Ch* StringType; static bool Is(const ValueType& v) { return v.IsString(); } static StringType Get(const ValueType& v) { return v.GetString(); } static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); } static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } }; #if RAPIDJSON_HAS_STDSTRING template struct TypeHelper > { typedef std::basic_string StringType; static bool Is(const ValueType& v) { return v.IsString(); } static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); } static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } }; #endif template struct TypeHelper { typedef typename ValueType::Array ArrayType; static bool Is(const ValueType& v) { return v.IsArray(); } static ArrayType Get(ValueType& v) { return v.GetArray(); } static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } }; template struct TypeHelper { typedef typename ValueType::ConstArray ArrayType; static bool Is(const ValueType& v) { return v.IsArray(); } static ArrayType Get(const ValueType& v) { return v.GetArray(); } }; template struct TypeHelper { typedef typename ValueType::Object ObjectType; static bool Is(const ValueType& v) { return v.IsObject(); } static ObjectType Get(ValueType& v) { return v.GetObject(); } static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; } }; template struct TypeHelper { typedef typename ValueType::ConstObject ObjectType; static bool Is(const ValueType& v) { return v.IsObject(); } static ObjectType Get(const ValueType& v) { return v.GetObject(); } }; } // namespace internal // Forward declarations template class GenericArray; template class GenericObject; /////////////////////////////////////////////////////////////////////////////// // GenericValue //! Represents a JSON value. Use Value for UTF8 encoding and default allocator. /*! A JSON value can be one of 7 types. This class is a variant type supporting these types. Use the Value if UTF8 and default allocator \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) \tparam Allocator Allocator type for allocating memory of object, array and string. */ template > class GenericValue { public: //! Name-value pair in an object. typedef GenericMember Member; typedef Encoding EncodingType; //!< Encoding type from template parameter. typedef Allocator AllocatorType; //!< Allocator type from template parameter. typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef GenericStringRef StringRefType; //!< Reference to a constant string typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. typedef GenericValue ValueType; //!< Value type of itself. typedef GenericArray Array; typedef GenericArray ConstArray; typedef GenericObject Object; typedef GenericObject ConstObject; //!@name Constructors and destructor. //@{ //! Default constructor creates a null value. GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) { rhs.data_.f.flags = kNullFlag; // give up contents } #endif private: //! Copy constructor is not permitted. GenericValue(const GenericValue& rhs); #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Moving from a GenericDocument is not permitted. template GenericValue(GenericDocument&& rhs); //! Move assignment from a GenericDocument is not permitted. template GenericValue& operator=(GenericDocument&& rhs); #endif public: //! Constructor with JSON value type. /*! This creates a Value of specified type with default content. \param type Type of the value. \note Default content for number is zero. */ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { static const uint16_t defaultFlags[7] = { kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, kNumberAnyFlag }; RAPIDJSON_ASSERT(type <= kNumberType); data_.f.flags = defaultFlags[type]; // Use ShortString to store empty string. if (type == kStringType) data_.ss.SetLength(0); } //! Explicit copy constructor (with allocator) /*! Creates a copy of a Value by using the given Allocator \tparam SourceAllocator allocator of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). \see CopyFrom() */ template< typename SourceAllocator > GenericValue(const GenericValue& rhs, Allocator & allocator); //! Constructor for boolean value. /*! \param b Boolean value \note This constructor is limited to \em real boolean values and rejects implicitly converted types like arbitrary pointers. Use an explicit cast to \c bool, if you want to construct a boolean JSON value in such cases. */ #ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen template explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT // See #472 #else explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT #endif : data_() { // safe-guard against failing SFINAE RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); data_.f.flags = b ? kTrueFlag : kFalseFlag; } //! Constructor for int value. explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() { data_.n.i64 = i; data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag; } //! Constructor for unsigned value. explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() { data_.n.u64 = u; data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag); } //! Constructor for int64_t value. explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() { data_.n.i64 = i64; data_.f.flags = kNumberInt64Flag; if (i64 >= 0) { data_.f.flags |= kNumberUint64Flag; if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) data_.f.flags |= kUintFlag; if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) data_.f.flags |= kIntFlag; } else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) data_.f.flags |= kIntFlag; } //! Constructor for uint64_t value. explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() { data_.n.u64 = u64; data_.f.flags = kNumberUint64Flag; if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) data_.f.flags |= kInt64Flag; if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) data_.f.flags |= kUintFlag; if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) data_.f.flags |= kIntFlag; } //! Constructor for double value. explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } //! Constructor for constant string (i.e. do not make a copy of string) GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } //! Constructor for constant string (i.e. do not make a copy of string) explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); } //! Constructor for copy-string (i.e. do make a copy of string) GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); } //! Constructor for copy-string (i.e. do make a copy of string) GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } #if RAPIDJSON_HAS_STDSTRING //! Constructor for copy-string from a string object (i.e. do make a copy of string) /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ GenericValue(const std::basic_string& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } #endif //! Constructor for Array. /*! \param a An array obtained by \c GetArray(). \note \c Array is always pass-by-value. \note the source array is moved into this value and the sourec array becomes empty. */ GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { a.value_.data_ = Data(); a.value_.data_.f.flags = kArrayFlag; } //! Constructor for Object. /*! \param o An object obtained by \c GetObject(). \note \c Object is always pass-by-value. \note the source object is moved into this value and the sourec object becomes empty. */ GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { o.value_.data_ = Data(); o.value_.data_.f.flags = kObjectFlag; } //! Destructor. /*! Need to destruct elements of array, members of object, or copy-string. */ ~GenericValue() { if (Allocator::kNeedFree) { // Shortcut by Allocator's trait switch(data_.f.flags) { case kArrayFlag: { GenericValue* e = GetElementsPointer(); for (GenericValue* v = e; v != e + data_.a.size; ++v) v->~GenericValue(); Allocator::Free(e); } break; case kObjectFlag: for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) m->~Member(); Allocator::Free(GetMembersPointer()); break; case kCopyStringFlag: Allocator::Free(const_cast(GetStringPointer())); break; default: break; // Do nothing for other types. } } } //@} //!@name Assignment operators //@{ //! Assignment with move semantics. /*! \param rhs Source of the assignment. It will become a null value after assignment. */ GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { RAPIDJSON_ASSERT(this != &rhs); this->~GenericValue(); RawAssign(rhs); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move assignment in C++11 GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { return *this = rhs.Move(); } #endif //! Assignment of constant string reference (no copy) /*! \param str Constant string reference to be assigned \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. \see GenericStringRef, operator=(T) */ GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { GenericValue s(str); return *this = s; } //! Assignment with primitive types. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param value The value to be assigned. \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref SetString(const Ch*, Allocator&) (for copying) or \ref StringRef() (to explicitly mark the pointer as constant) instead. All other pointer types would implicitly convert to \c bool, use \ref SetBool() instead. */ template RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) operator=(T value) { GenericValue v(value); return *this = v; } //! Deep-copy assignment from Value /*! Assigns a \b copy of the Value to the current Value object \tparam SourceAllocator Allocator type of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator to use for copying */ template GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) { RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); this->~GenericValue(); new (this) GenericValue(rhs, allocator); return *this; } //! Exchange the contents of this value with those of other. /*! \param other Another value. \note Constant complexity. */ GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { GenericValue temp; temp.RawAssign(*this); RawAssign(other); other.RawAssign(temp); return *this; } //! free-standing swap function helper /*! Helper function to enable support for common swap implementation pattern based on \c std::swap: \code void swap(MyClass& a, MyClass& b) { using std::swap; swap(a.value, b.value); // ... } \endcode \see Swap() */ friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } //! Prepare Value for move semantics /*! \return *this */ GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } //@} //!@name Equal-to and not-equal-to operators //@{ //! Equal-to operator /*! \note If an object contains duplicated named member, comparing equality with any object is always \c false. \note Linear time complexity (number of all values in the subtree and total lengths of all strings). */ template bool operator==(const GenericValue& rhs) const { typedef GenericValue RhsType; if (GetType() != rhs.GetType()) return false; switch (GetType()) { case kObjectType: // Warning: O(n^2) inner-loop if (data_.o.size != rhs.data_.o.size) return false; for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) return false; } return true; case kArrayType: if (data_.a.size != rhs.data_.a.size) return false; for (SizeType i = 0; i < data_.a.size; i++) if ((*this)[i] != rhs[i]) return false; return true; case kStringType: return StringEqual(rhs); case kNumberType: if (IsDouble() || rhs.IsDouble()) { double a = GetDouble(); // May convert from integer to double. double b = rhs.GetDouble(); // Ditto return a >= b && a <= b; // Prevent -Wfloat-equal } else return data_.n.u64 == rhs.data_.n.u64; default: return true; } } //! Equal-to operator with const C-string pointer bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } #if RAPIDJSON_HAS_STDSTRING //! Equal-to operator with string object /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); } #endif //! Equal-to operator with primitive types /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } //! Not-equal-to operator /*! \return !(*this == rhs) */ template bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } //! Not-equal-to operator with const C-string pointer bool operator!=(const Ch* rhs) const { return !(*this == rhs); } //! Not-equal-to operator with arbitrary types /*! \return !(*this == rhs) */ template RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } //! Equal-to operator with arbitrary types (symmetric version) /*! \return (rhs == lhs) */ template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } //! Not-Equal-to operator with arbitrary types (symmetric version) /*! \return !(rhs == lhs) */ template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } //@} //!@name Type //@{ Type GetType() const { return static_cast(data_.f.flags & kTypeMask); } bool IsNull() const { return data_.f.flags == kNullFlag; } bool IsFalse() const { return data_.f.flags == kFalseFlag; } bool IsTrue() const { return data_.f.flags == kTrueFlag; } bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; } bool IsObject() const { return data_.f.flags == kObjectFlag; } bool IsArray() const { return data_.f.flags == kArrayFlag; } bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; } bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; } bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; } bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; } bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; } bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; } bool IsString() const { return (data_.f.flags & kStringFlag) != 0; } // Checks whether a number can be losslessly converted to a double. bool IsLosslessDouble() const { if (!IsNumber()) return false; if (IsUint64()) { uint64_t u = GetUint64(); volatile double d = static_cast(u); return (d >= 0.0) && (d < static_cast(std::numeric_limits::max())) && (u == static_cast(d)); } if (IsInt64()) { int64_t i = GetInt64(); volatile double d = static_cast(i); return (d >= static_cast(std::numeric_limits::min())) && (d < static_cast(std::numeric_limits::max())) && (i == static_cast(d)); } return true; // double, int, uint are always lossless } // Checks whether a number is a float (possible lossy). bool IsFloat() const { if ((data_.f.flags & kDoubleFlag) == 0) return false; double d = GetDouble(); return d >= -3.4028234e38 && d <= 3.4028234e38; } // Checks whether a number can be losslessly converted to a float. bool IsLosslessFloat() const { if (!IsNumber()) return false; double a = GetDouble(); if (a < static_cast(-std::numeric_limits::max()) || a > static_cast(std::numeric_limits::max())) return false; double b = static_cast(static_cast(a)); return a >= b && a <= b; // Prevent -Wfloat-equal } //@} //!@name Null //@{ GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } //@} //!@name Bool //@{ bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; } //!< Set boolean value /*! \post IsBool() == true */ GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } //@} //!@name Object //@{ //! Set this value as an empty object. /*! \post IsObject() == true */ GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } //! Get the number of members in the object. SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } //! Check whether the object is empty. bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } //! Get a value from an object associated with the name. /*! \pre IsObject() == true \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. Since 0.2, if the name is not correct, it will assert. If user is unsure whether a member exists, user should use HasMember() first. A better approach is to use FindMember(). \note Linear time complexity. */ template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) { GenericValue n(StringRef(name)); return (*this)[n]; } template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; } //! Get a value from an object associated with the name. /*! \pre IsObject() == true \tparam SourceAllocator Allocator of the \c name value \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). And it can also handle strings with embedded null characters. \note Linear time complexity. */ template GenericValue& operator[](const GenericValue& name) { MemberIterator member = FindMember(name); if (member != MemberEnd()) return member->value; else { RAPIDJSON_ASSERT(false); // see above note // This will generate -Wexit-time-destructors in clang // static GenericValue NullValue; // return NullValue; // Use static buffer and placement-new to prevent destruction static char buffer[sizeof(GenericValue)]; return *new (buffer) GenericValue(); } } template const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } #if RAPIDJSON_HAS_STDSTRING //! Get a value from an object associated with name (string object). GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; } const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; } #endif //! Const member iterator /*! \pre IsObject() == true */ ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); } //! Const \em past-the-end member iterator /*! \pre IsObject() == true */ ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); } //! Member iterator /*! \pre IsObject() == true */ MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); } //! \em Past-the-end member iterator /*! \pre IsObject() == true */ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } //! Check whether a member exists in the object. /*! \param name Member name to be searched. \pre IsObject() == true \return Whether a member with that name exists. \note It is better to use FindMember() directly if you need the obtain the value as well. \note Linear time complexity. */ bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } #if RAPIDJSON_HAS_STDSTRING //! Check whether a member exists in the object with string object. /*! \param name Member name to be searched. \pre IsObject() == true \return Whether a member with that name exists. \note It is better to use FindMember() directly if you need the obtain the value as well. \note Linear time complexity. */ bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); } #endif //! Check whether a member exists in the object with GenericValue name. /*! This version is faster because it does not need a StrLen(). It can also handle string with null character. \param name Member name to be searched. \pre IsObject() == true \return Whether a member with that name exists. \note It is better to use FindMember() directly if you need the obtain the value as well. \note Linear time complexity. */ template bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } //! Find member by name. /*! \param name Member name to be searched. \pre IsObject() == true \return Iterator to member, if it exists. Otherwise returns \ref MemberEnd(). \note Earlier versions of Rapidjson returned a \c NULL pointer, in case the requested member doesn't exist. For consistency with e.g. \c std::map, this has been changed to MemberEnd() now. \note Linear time complexity. */ MemberIterator FindMember(const Ch* name) { GenericValue n(StringRef(name)); return FindMember(n); } ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } //! Find member by name. /*! This version is faster because it does not need a StrLen(). It can also handle string with null character. \param name Member name to be searched. \pre IsObject() == true \return Iterator to member, if it exists. Otherwise returns \ref MemberEnd(). \note Earlier versions of Rapidjson returned a \c NULL pointer, in case the requested member doesn't exist. For consistency with e.g. \c std::map, this has been changed to MemberEnd() now. \note Linear time complexity. */ template MemberIterator FindMember(const GenericValue& name) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); MemberIterator member = MemberBegin(); for ( ; member != MemberEnd(); ++member) if (name.StringEqual(member->name)) break; return member; } template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } #if RAPIDJSON_HAS_STDSTRING //! Find member by string object name. /*! \param name Member name to be searched. \pre IsObject() == true \return Iterator to member, if it exists. Otherwise returns \ref MemberEnd(). */ MemberIterator FindMember(const std::basic_string& name) { return FindMember(GenericValue(StringRef(name))); } ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(GenericValue(StringRef(name))); } #endif //! Add a member (name-value pair) to the object. /*! \param name A string value as name of member. \param value Value of any type. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \note The ownership of \c name and \c value will be transferred to this object on success. \pre IsObject() && name.IsString() \post name.IsNull() && value.IsNull() \note Amortized Constant time complexity. */ GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); ObjectData& o = data_.o; if (o.size >= o.capacity) { if (o.capacity == 0) { o.capacity = kDefaultObjectCapacity; SetMembersPointer(reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member)))); } else { SizeType oldCapacity = o.capacity; o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member)))); } } Member* members = GetMembersPointer(); members[o.size].name.RawAssign(name); members[o.size].value.RawAssign(value); o.size++; return *this; } //! Add a constant string value as member (name-value pair) to the object. /*! \param name A string value as name of member. \param value constant string reference as value of member. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. \note Amortized Constant time complexity. */ GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { GenericValue v(value); return AddMember(name, v, allocator); } #if RAPIDJSON_HAS_STDSTRING //! Add a string object as member (name-value pair) to the object. /*! \param name A string value as name of member. \param value constant string reference as value of member. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. \note Amortized Constant time complexity. */ GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { GenericValue v(value, allocator); return AddMember(name, v, allocator); } #endif //! Add any primitive value as member (name-value pair) to the object. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param name A string value as name of member. \param value Value of primitive type \c T as value of member \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref AddMember(StringRefType, StringRefType, Allocator&). All other pointer types would implicitly convert to \c bool, use an explicit cast instead, if needed. \note Amortized Constant time complexity. */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) AddMember(GenericValue& name, T value, Allocator& allocator) { GenericValue v(value); return AddMember(name, v, allocator); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { return AddMember(name, value, allocator); } GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { return AddMember(name, value, allocator); } GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { return AddMember(name, value, allocator); } GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { GenericValue n(name); return AddMember(n, value, allocator); } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Add a member (name-value pair) to the object. /*! \param name A constant string reference as name of member. \param value Value of any type. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \note The ownership of \c value will be transferred to this object on success. \pre IsObject() \post value.IsNull() \note Amortized Constant time complexity. */ GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { GenericValue n(name); return AddMember(n, value, allocator); } //! Add a constant string value as member (name-value pair) to the object. /*! \param name A constant string reference as name of member. \param value constant string reference as value of member. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. \note Amortized Constant time complexity. */ GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { GenericValue v(value); return AddMember(name, v, allocator); } //! Add any primitive value as member (name-value pair) to the object. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param name A constant string reference as name of member. \param value Value of primitive type \c T as value of member \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref AddMember(StringRefType, StringRefType, Allocator&). All other pointer types would implicitly convert to \c bool, use an explicit cast instead, if needed. \note Amortized Constant time complexity. */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) AddMember(StringRefType name, T value, Allocator& allocator) { GenericValue n(name); return AddMember(n, value, allocator); } //! Remove all members in the object. /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. \note Linear time complexity. */ void RemoveAllMembers() { RAPIDJSON_ASSERT(IsObject()); for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) m->~Member(); data_.o.size = 0; } //! Remove a member in object by its name. /*! \param name Name of member to be removed. \return Whether the member existed. \note This function may reorder the object members. Use \ref EraseMember(ConstMemberIterator) if you need to preserve the relative order of the remaining members. \note Linear time complexity. */ bool RemoveMember(const Ch* name) { GenericValue n(StringRef(name)); return RemoveMember(n); } #if RAPIDJSON_HAS_STDSTRING bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } #endif template bool RemoveMember(const GenericValue& name) { MemberIterator m = FindMember(name); if (m != MemberEnd()) { RemoveMember(m); return true; } else return false; } //! Remove a member in object by iterator. /*! \param m member iterator (obtained by FindMember() or MemberBegin()). \return the new iterator after removal. \note This function may reorder the object members. Use \ref EraseMember(ConstMemberIterator) if you need to preserve the relative order of the remaining members. \note Constant time complexity. */ MemberIterator RemoveMember(MemberIterator m) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(data_.o.size > 0); RAPIDJSON_ASSERT(GetMembersPointer() != 0); RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); MemberIterator last(GetMembersPointer() + (data_.o.size - 1)); if (data_.o.size > 1 && m != last) *m = *last; // Move the last one to this place else m->~Member(); // Only one left, just destroy --data_.o.size; return m; } //! Remove a member from an object by iterator. /*! \param pos iterator to the member to remove \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() \return Iterator following the removed element. If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. \note This function preserves the relative order of the remaining object members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). \note Linear time complexity. */ MemberIterator EraseMember(ConstMemberIterator pos) { return EraseMember(pos, pos +1); } //! Remove members in the range [first, last) from an object. /*! \param first iterator to the first member to remove \param last iterator following the last member to remove \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() \return Iterator following the last removed element. \note This function preserves the relative order of the remaining object members. \note Linear time complexity. */ MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(data_.o.size > 0); RAPIDJSON_ASSERT(GetMembersPointer() != 0); RAPIDJSON_ASSERT(first >= MemberBegin()); RAPIDJSON_ASSERT(first <= last); RAPIDJSON_ASSERT(last <= MemberEnd()); MemberIterator pos = MemberBegin() + (first - MemberBegin()); for (MemberIterator itr = pos; itr != last; ++itr) itr->~Member(); std::memmove(&*pos, &*last, static_cast(MemberEnd() - last) * sizeof(Member)); data_.o.size -= static_cast(last - first); return pos; } //! Erase a member in object by its name. /*! \param name Name of member to be removed. \return Whether the member existed. \note Linear time complexity. */ bool EraseMember(const Ch* name) { GenericValue n(StringRef(name)); return EraseMember(n); } #if RAPIDJSON_HAS_STDSTRING bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } #endif template bool EraseMember(const GenericValue& name) { MemberIterator m = FindMember(name); if (m != MemberEnd()) { EraseMember(m); return true; } else return false; } Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } //@} //!@name Array //@{ //! Set this value as an empty array. /*! \post IsArray == true */ GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } //! Get the number of elements in array. SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } //! Get the capacity of array. SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } //! Check whether the array is empty. bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } //! Remove all elements in the array. /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. \note Linear time complexity. */ void Clear() { RAPIDJSON_ASSERT(IsArray()); GenericValue* e = GetElementsPointer(); for (GenericValue* v = e; v != e + data_.a.size; ++v) v->~GenericValue(); data_.a.size = 0; } //! Get an element from array by index. /*! \pre IsArray() == true \param index Zero-based index of element. \see operator[](T*) */ GenericValue& operator[](SizeType index) { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(index < data_.a.size); return GetElementsPointer()[index]; } const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } //! Element iterator /*! \pre IsArray() == true */ ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); } //! \em Past-the-end element iterator /*! \pre IsArray() == true */ ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; } //! Constant element iterator /*! \pre IsArray() == true */ ConstValueIterator Begin() const { return const_cast(*this).Begin(); } //! Constant \em past-the-end element iterator /*! \pre IsArray() == true */ ConstValueIterator End() const { return const_cast(*this).End(); } //! Request the array to have enough capacity to store elements. /*! \param newCapacity The capacity that the array at least need to have. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \note Linear time complexity. */ GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { RAPIDJSON_ASSERT(IsArray()); if (newCapacity > data_.a.capacity) { SetElementsPointer(reinterpret_cast(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)))); data_.a.capacity = newCapacity; } return *this; } //! Append a GenericValue at the end of the array. /*! \param value Value to be appended. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \pre IsArray() == true \post value.IsNull() == true \return The value itself for fluent API. \note The ownership of \c value will be transferred to this array on success. \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. \note Amortized constant time complexity. */ GenericValue& PushBack(GenericValue& value, Allocator& allocator) { RAPIDJSON_ASSERT(IsArray()); if (data_.a.size >= data_.a.capacity) Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); GetElementsPointer()[data_.a.size++].RawAssign(value); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { return PushBack(value, allocator); } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Append a constant string reference at the end of the array. /*! \param value Constant string reference to be appended. \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). \pre IsArray() == true \return The value itself for fluent API. \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. \note Amortized constant time complexity. \see GenericStringRef */ GenericValue& PushBack(StringRefType value, Allocator& allocator) { return (*this).template PushBack(value, allocator); } //! Append a primitive value at the end of the array. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param value Value of primitive type T to be appended. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \pre IsArray() == true \return The value itself for fluent API. \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref PushBack(GenericValue&, Allocator&) or \ref PushBack(StringRefType, Allocator&). All other pointer types would implicitly convert to \c bool, use an explicit cast instead, if needed. \note Amortized constant time complexity. */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) PushBack(T value, Allocator& allocator) { GenericValue v(value); return PushBack(v, allocator); } //! Remove the last element in the array. /*! \note Constant time complexity. */ GenericValue& PopBack() { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(!Empty()); GetElementsPointer()[--data_.a.size].~GenericValue(); return *this; } //! Remove an element of array by iterator. /*! \param pos iterator to the element to remove \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. \note Linear time complexity. */ ValueIterator Erase(ConstValueIterator pos) { return Erase(pos, pos + 1); } //! Remove elements in the range [first, last) of the array. /*! \param first iterator to the first element to remove \param last iterator following the last element to remove \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() \return Iterator following the last removed element. \note Linear time complexity. */ ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(data_.a.size > 0); RAPIDJSON_ASSERT(GetElementsPointer() != 0); RAPIDJSON_ASSERT(first >= Begin()); RAPIDJSON_ASSERT(first <= last); RAPIDJSON_ASSERT(last <= End()); ValueIterator pos = Begin() + (first - Begin()); for (ValueIterator itr = pos; itr != last; ++itr) itr->~GenericValue(); std::memmove(pos, last, static_cast(End() - last) * sizeof(GenericValue)); data_.a.size -= static_cast(last - first); return pos; } Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } //@} //!@name Number //@{ int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; } unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; } int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; } uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; } //! Get the value as double type. /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless. */ double GetDouble() const { RAPIDJSON_ASSERT(IsNumber()); if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double if ((data_.f.flags & kInt64Flag) != 0) return static_cast(data_.n.i64); // int64_t -> double (may lose precision) RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast(data_.n.u64); // uint64_t -> double (may lose precision) } //! Get the value as float type. /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless. */ float GetFloat() const { return static_cast(GetDouble()); } GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(f); return *this; } //@} //!@name String //@{ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); } //! Get the length of string. /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). */ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } //! Set this value as a string without copying source string. /*! This version has better performance with supplied length, and also support string containing null character. \param s source string pointer. \param length The length of source string, excluding the trailing null terminator. \return The value itself for fluent API. \post IsString() == true && GetString() == s && GetStringLength() == length \see SetString(StringRefType) */ GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } //! Set this value as a string without copying source string. /*! \param s source string reference \return The value itself for fluent API. \post IsString() == true && GetString() == s && GetStringLength() == s.length */ GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } //! Set this value as a string by copying from source string. /*! This version has better performance with supplied length, and also support string containing null character. \param s source string. \param length The length of source string, excluding the trailing null terminator. \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; } //! Set this value as a string by copying from source string. /*! \param s source string. \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } #if RAPIDJSON_HAS_STDSTRING //! Set this value as a string by copying from source string. /*! \param s source string. \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); } #endif //@} //!@name Array //@{ //! Templated version for checking whether this value is type T. /*! \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string */ template bool Is() const { return internal::TypeHelper::Is(*this); } template T Get() const { return internal::TypeHelper::Get(*this); } template T Get() { return internal::TypeHelper::Get(*this); } template ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); } template ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); } //@} //! Generate events of this value to a Handler. /*! This function adopts the GoF visitor pattern. Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. It can also be used to deep clone this value via GenericDocument, which is also a Handler. \tparam Handler type of handler. \param handler An object implementing concept Handler. */ template bool Accept(Handler& handler) const { switch(GetType()) { case kNullType: return handler.Null(); case kFalseType: return handler.Bool(false); case kTrueType: return handler.Bool(true); case kObjectType: if (RAPIDJSON_UNLIKELY(!handler.StartObject())) return false; for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) return false; if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) return false; } return handler.EndObject(data_.o.size); case kArrayType: if (RAPIDJSON_UNLIKELY(!handler.StartArray())) return false; for (const GenericValue* v = Begin(); v != End(); ++v) if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) return false; return handler.EndArray(data_.a.size); case kStringType: return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); default: RAPIDJSON_ASSERT(GetType() == kNumberType); if (IsDouble()) return handler.Double(data_.n.d); else if (IsInt()) return handler.Int(data_.n.i.i); else if (IsUint()) return handler.Uint(data_.n.u.u); else if (IsInt64()) return handler.Int64(data_.n.i64); else return handler.Uint64(data_.n.u64); } } private: template friend class GenericValue; template friend class GenericDocument; enum { kBoolFlag = 0x0008, kNumberFlag = 0x0010, kIntFlag = 0x0020, kUintFlag = 0x0040, kInt64Flag = 0x0080, kUint64Flag = 0x0100, kDoubleFlag = 0x0200, kStringFlag = 0x0400, kCopyFlag = 0x0800, kInlineStrFlag = 0x1000, // Initial flags of different types. kNullFlag = kNullType, kTrueFlag = kTrueType | kBoolFlag, kFalseFlag = kFalseType | kBoolFlag, kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, kConstStringFlag = kStringType | kStringFlag, kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag, kObjectFlag = kObjectType, kArrayFlag = kArrayType, kTypeMask = 0x07 }; static const SizeType kDefaultArrayCapacity = 16; static const SizeType kDefaultObjectCapacity = 16; struct Flag { #if RAPIDJSON_48BITPOINTER_OPTIMIZATION char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer #elif RAPIDJSON_64BIT char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes #else char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes #endif uint16_t flags; }; struct String { SizeType length; SizeType hashcode; //!< reserved const Ch* str; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars // (excluding the terminating zero) and store a value to determine the length of the contained // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as // the string terminator as well. For getting the string length back from that value just use // "MaxSize - str[LenPos]". // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode, // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings). struct ShortString { enum { MaxChars = sizeof(static_cast(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; Ch str[MaxChars]; inline static bool Usable(SizeType len) { return (MaxSize >= len); } inline void SetLength(SizeType len) { str[LenPos] = static_cast(MaxSize - len); } inline SizeType GetLength() const { return static_cast(MaxSize - str[LenPos]); } }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // By using proper binary layout, retrieval of different integer types do not need conversions. union Number { #if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN struct I { int i; char padding[4]; }i; struct U { unsigned u; char padding2[4]; }u; #else struct I { char padding[4]; int i; }i; struct U { char padding2[4]; unsigned u; }u; #endif int64_t i64; uint64_t u64; double d; }; // 8 bytes struct ObjectData { SizeType size; SizeType capacity; Member* members; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode struct ArrayData { SizeType size; SizeType capacity; GenericValue* elements; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode union Data { String s; ShortString ss; Number n; ObjectData o; ArrayData a; Flag f; }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); } RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); } RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } // Initialize this value as array with initial data, without calling destructor. void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { data_.f.flags = kArrayFlag; if (count) { GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); SetElementsPointer(e); std::memcpy(e, values, count * sizeof(GenericValue)); } else SetElementsPointer(0); data_.a.size = data_.a.capacity = count; } //! Initialize this value as object with initial data, without calling destructor. void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { data_.f.flags = kObjectFlag; if (count) { Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); SetMembersPointer(m); std::memcpy(m, members, count * sizeof(Member)); } else SetMembersPointer(0); data_.o.size = data_.o.capacity = count; } //! Initialize this value as constant string, without calling destructor. void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { data_.f.flags = kConstStringFlag; SetStringPointer(s); data_.s.length = s.length; } //! Initialize this value as copy string with initial data, without calling destructor. void SetStringRaw(StringRefType s, Allocator& allocator) { Ch* str = 0; if (ShortString::Usable(s.length)) { data_.f.flags = kShortStringFlag; data_.ss.SetLength(s.length); str = data_.ss.str; } else { data_.f.flags = kCopyStringFlag; data_.s.length = s.length; str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch))); SetStringPointer(str); } std::memcpy(str, s, s.length * sizeof(Ch)); str[s.length] = '\0'; } //! Assignment without calling destructor void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { data_ = rhs.data_; // data_.f.flags = rhs.data_.f.flags; rhs.data_.f.flags = kNullFlag; } template bool StringEqual(const GenericValue& rhs) const { RAPIDJSON_ASSERT(IsString()); RAPIDJSON_ASSERT(rhs.IsString()); const SizeType len1 = GetStringLength(); const SizeType len2 = rhs.GetStringLength(); if(len1 != len2) { return false; } const Ch* const str1 = GetString(); const Ch* const str2 = rhs.GetString(); if(str1 == str2) { return true; } // fast path for constant string return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); } Data data_; }; //! GenericValue with UTF8 encoding typedef GenericValue > Value; /////////////////////////////////////////////////////////////////////////////// // GenericDocument //! A document for parsing JSON text as DOM. /*! \note implements Handler concept \tparam Encoding Encoding for both parsing and string storage. \tparam Allocator Allocator for allocating memory for the DOM \tparam StackAllocator Allocator for allocating memory for stack during parsing. \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. */ template , typename StackAllocator = CrtAllocator> class GenericDocument : public GenericValue { public: typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef GenericValue ValueType; //!< Value type of the document. typedef Allocator AllocatorType; //!< Allocator type from template parameter. //! Constructor /*! Creates an empty document of specified type. \param type Mandatory type of object to create. \param allocator Optional allocator for allocating memory. \param stackCapacity Optional initial capacity of stack in bytes. \param stackAllocator Optional allocator for allocating memory for stack. */ explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); } //! Constructor /*! Creates an empty document which type is Null. \param allocator Optional allocator for allocating memory. \param stackCapacity Optional initial capacity of stack in bytes. \param stackAllocator Optional allocator for allocating memory for stack. */ GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT : ValueType(std::forward(rhs)), // explicit cast to avoid prohibited move from Document allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), stack_(std::move(rhs.stack_)), parseResult_(rhs.parseResult_) { rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.parseResult_ = ParseResult(); } #endif ~GenericDocument() { Destroy(); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move assignment in C++11 GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT { // The cast to ValueType is necessary here, because otherwise it would // attempt to call GenericValue's templated assignment operator. ValueType::operator=(std::forward(rhs)); // Calling the destructor here would prematurely call stack_'s destructor Destroy(); allocator_ = rhs.allocator_; ownAllocator_ = rhs.ownAllocator_; stack_ = std::move(rhs.stack_); parseResult_ = rhs.parseResult_; rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.parseResult_ = ParseResult(); return *this; } #endif //! Exchange the contents of this document with those of another. /*! \param rhs Another document. \note Constant complexity. \see GenericValue::Swap */ GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { ValueType::Swap(rhs); stack_.Swap(rhs.stack_); internal::Swap(allocator_, rhs.allocator_); internal::Swap(ownAllocator_, rhs.ownAllocator_); internal::Swap(parseResult_, rhs.parseResult_); return *this; } //! free-standing swap function helper /*! Helper function to enable support for common swap implementation pattern based on \c std::swap: \code void swap(MyClass& a, MyClass& b) { using std::swap; swap(a.doc, b.doc); // ... } \endcode \see Swap() */ friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } //! Populate this document by a generator which produces SAX events. /*! \tparam Generator A functor with bool f(Handler) prototype. \param g Generator functor which sends SAX events to the parameter. \return The document itself for fluent API. */ template GenericDocument& Populate(Generator& g) { ClearStackOnExit scope(*this); if (g(*this)) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document } return *this; } //!@name Parse from stream //!@{ //! Parse JSON text from an input stream (with Encoding conversion) /*! \tparam parseFlags Combination of \ref ParseFlag. \tparam SourceEncoding Encoding of input stream \tparam InputStream Type of input stream, implementing Stream concept \param is Input stream to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseStream(InputStream& is) { GenericReader reader( stack_.HasAllocator() ? &stack_.GetAllocator() : 0); ClearStackOnExit scope(*this); parseResult_ = reader.template Parse(is, *this); if (parseResult_) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document } return *this; } //! Parse JSON text from an input stream /*! \tparam parseFlags Combination of \ref ParseFlag. \tparam InputStream Type of input stream, implementing Stream concept \param is Input stream to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseStream(InputStream& is) { return ParseStream(is); } //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) /*! \tparam InputStream Type of input stream, implementing Stream concept \param is Input stream to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseStream(InputStream& is) { return ParseStream(is); } //!@} //!@name Parse in-place from mutable string //!@{ //! Parse JSON text from a mutable string /*! \tparam parseFlags Combination of \ref ParseFlag. \param str Mutable zero-terminated string to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseInsitu(Ch* str) { GenericInsituStringStream s(str); return ParseStream(s); } //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) /*! \param str Mutable zero-terminated string to be parsed. \return The document itself for fluent API. */ GenericDocument& ParseInsitu(Ch* str) { return ParseInsitu(str); } //!@} //!@name Parse from read-only string //!@{ //! Parse JSON text from a read-only string (with Encoding conversion) /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). \tparam SourceEncoding Transcoding from input Encoding \param str Read-only zero-terminated string to be parsed. */ template GenericDocument& Parse(const typename SourceEncoding::Ch* str) { RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); GenericStringStream s(str); return ParseStream(s); } //! Parse JSON text from a read-only string /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). \param str Read-only zero-terminated string to be parsed. */ template GenericDocument& Parse(const Ch* str) { return Parse(str); } //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) /*! \param str Read-only zero-terminated string to be parsed. */ GenericDocument& Parse(const Ch* str) { return Parse(str); } template GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); MemoryStream ms(static_cast(str), length * sizeof(typename SourceEncoding::Ch)); EncodedInputStream is(ms); ParseStream(is); return *this; } template GenericDocument& Parse(const Ch* str, size_t length) { return Parse(str, length); } GenericDocument& Parse(const Ch* str, size_t length) { return Parse(str, length); } #if RAPIDJSON_HAS_STDSTRING template GenericDocument& Parse(const std::basic_string& str) { // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t) return Parse(str.c_str()); } template GenericDocument& Parse(const std::basic_string& str) { return Parse(str.c_str()); } GenericDocument& Parse(const std::basic_string& str) { return Parse(str); } #endif // RAPIDJSON_HAS_STDSTRING //!@} //!@name Handling parse errors //!@{ //! Whether a parse error has occured in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } //! Get the \ref ParseErrorCode of last parsing. ParseErrorCode GetParseError() const { return parseResult_.Code(); } //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } //! Implicit conversion to get the last parse result #ifndef __clang // -Wdocumentation /*! \return \ref ParseResult of the last parse operation \code Document doc; ParseResult ok = doc.Parse(json); if (!ok) printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); \endcode */ #endif operator ParseResult() const { return parseResult_; } //!@} //! Get the allocator of this document. Allocator& GetAllocator() { RAPIDJSON_ASSERT(allocator_); return *allocator_; } //! Get the capacity of stack in bytes. size_t GetStackCapacity() const { return stack_.GetCapacity(); } private: // clear stack on any exit from ParseStream, e.g. due to exception struct ClearStackOnExit { explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} ~ClearStackOnExit() { d_.ClearStack(); } private: ClearStackOnExit(const ClearStackOnExit&); ClearStackOnExit& operator=(const ClearStackOnExit&); GenericDocument& d_; }; // callers of the following private Handler functions // template friend class GenericReader; // for parsing template friend class GenericValue; // for deep copying public: // Implementation of Handler bool Null() { new (stack_.template Push()) ValueType(); return true; } bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } bool RawNumber(const Ch* str, SizeType length, bool copy) { if (copy) new (stack_.template Push()) ValueType(str, length, GetAllocator()); else new (stack_.template Push()) ValueType(str, length); return true; } bool String(const Ch* str, SizeType length, bool copy) { if (copy) new (stack_.template Push()) ValueType(str, length, GetAllocator()); else new (stack_.template Push()) ValueType(str, length); return true; } bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } bool EndObject(SizeType memberCount) { typename ValueType::Member* members = stack_.template Pop(memberCount); stack_.template Top()->SetObjectRaw(members, memberCount, GetAllocator()); return true; } bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } bool EndArray(SizeType elementCount) { ValueType* elements = stack_.template Pop(elementCount); stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); return true; } private: //! Prohibit copying GenericDocument(const GenericDocument&); //! Prohibit assignment GenericDocument& operator=(const GenericDocument&); void ClearStack() { if (Allocator::kNeedFree) while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) (stack_.template Pop(1))->~ValueType(); else stack_.Clear(); stack_.ShrinkToFit(); } void Destroy() { RAPIDJSON_DELETE(ownAllocator_); } static const size_t kDefaultStackCapacity = 1024; Allocator* allocator_; Allocator* ownAllocator_; internal::Stack stack_; ParseResult parseResult_; }; //! GenericDocument with UTF8 encoding typedef GenericDocument > Document; // defined here due to the dependency on GenericDocument template template inline GenericValue::GenericValue(const GenericValue& rhs, Allocator& allocator) { switch (rhs.GetType()) { case kObjectType: case kArrayType: { // perform deep copy via SAX Handler GenericDocument d(&allocator); rhs.Accept(d); RawAssign(*d.stack_.template Pop(1)); } break; case kStringType: if (rhs.data_.f.flags == kConstStringFlag) { data_.f.flags = rhs.data_.f.flags; data_ = *reinterpret_cast(&rhs.data_); } else { SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); } break; default: data_.f.flags = rhs.data_.f.flags; data_ = *reinterpret_cast(&rhs.data_); break; } } //! Helper class for accessing Value of array type. /*! Instance of this helper class is obtained by \c GenericValue::GetArray(). In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. */ template class GenericArray { public: typedef GenericArray ConstArray; typedef GenericArray Array; typedef ValueT PlainType; typedef typename internal::MaybeAddConst::Type ValueType; typedef ValueType* ValueIterator; // This may be const or non-const iterator typedef const ValueT* ConstValueIterator; typedef typename ValueType::AllocatorType AllocatorType; typedef typename ValueType::StringRefType StringRefType; template friend class GenericValue; GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } ~GenericArray() {} SizeType Size() const { return value_.Size(); } SizeType Capacity() const { return value_.Capacity(); } bool Empty() const { return value_.Empty(); } void Clear() const { value_.Clear(); } ValueType& operator[](SizeType index) const { return value_[index]; } ValueIterator Begin() const { return value_.Begin(); } ValueIterator End() const { return value_.End(); } GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; } GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } GenericArray PopBack() const { value_.PopBack(); return *this; } ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } #if RAPIDJSON_HAS_CXX11_RANGE_FOR ValueIterator begin() const { return value_.Begin(); } ValueIterator end() const { return value_.End(); } #endif private: GenericArray(); GenericArray(ValueType& value) : value_(value) {} ValueType& value_; }; //! Helper class for accessing Value of object type. /*! Instance of this helper class is obtained by \c GenericValue::GetObject(). In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. */ template class GenericObject { public: typedef GenericObject ConstObject; typedef GenericObject Object; typedef ValueT PlainType; typedef typename internal::MaybeAddConst::Type ValueType; typedef GenericMemberIterator MemberIterator; // This may be const or non-const iterator typedef GenericMemberIterator ConstMemberIterator; typedef typename ValueType::AllocatorType AllocatorType; typedef typename ValueType::StringRefType StringRefType; typedef typename ValueType::EncodingType EncodingType; typedef typename ValueType::Ch Ch; template friend class GenericValue; GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } ~GenericObject() {} SizeType MemberCount() const { return value_.MemberCount(); } bool ObjectEmpty() const { return value_.ObjectEmpty(); } template ValueType& operator[](T* name) const { return value_[name]; } template ValueType& operator[](const GenericValue& name) const { return value_[name]; } #if RAPIDJSON_HAS_STDSTRING ValueType& operator[](const std::basic_string& name) const { return value_[name]; } #endif MemberIterator MemberBegin() const { return value_.MemberBegin(); } MemberIterator MemberEnd() const { return value_.MemberEnd(); } bool HasMember(const Ch* name) const { return value_.HasMember(name); } #if RAPIDJSON_HAS_STDSTRING bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } #endif template bool HasMember(const GenericValue& name) const { return value_.HasMember(name); } MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); } template MemberIterator FindMember(const GenericValue& name) const { return value_.FindMember(name); } #if RAPIDJSON_HAS_STDSTRING MemberIterator FindMember(const std::basic_string& name) const { return value_.FindMember(name); } #endif GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #if RAPIDJSON_HAS_STDSTRING GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } void RemoveAllMembers() { return value_.RemoveAllMembers(); } bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } #if RAPIDJSON_HAS_STDSTRING bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } #endif template bool RemoveMember(const GenericValue& name) const { return value_.RemoveMember(name); } MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } #if RAPIDJSON_HAS_STDSTRING bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } #endif template bool EraseMember(const GenericValue& name) const { return value_.EraseMember(name); } #if RAPIDJSON_HAS_CXX11_RANGE_FOR MemberIterator begin() const { return value_.MemberBegin(); } MemberIterator end() const { return value_.MemberEnd(); } #endif private: GenericObject(); GenericObject(ValueType& value) : value_(value) {} ValueType& value_; }; RAPIDJSON_NAMESPACE_END RAPIDJSON_DIAG_POP #endif // RAPIDJSON_DOCUMENT_H_ osmium-tool-1.7.1/include/rapidjson/encodedstream.h000066400000000000000000000246761315004223400224170ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ENCODEDSTREAM_H_ #define RAPIDJSON_ENCODEDSTREAM_H_ #include "stream.h" #include "memorystream.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif RAPIDJSON_NAMESPACE_BEGIN //! Input byte stream wrapper with a statically bound encoding. /*! \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. \tparam InputByteStream Type of input byte stream. For example, FileReadStream. */ template class EncodedInputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); public: typedef typename Encoding::Ch Ch; EncodedInputStream(InputByteStream& is) : is_(is) { current_ = Encoding::TakeBOM(is_); } Ch Peek() const { return current_; } Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } size_t Tell() const { return is_.Tell(); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: EncodedInputStream(const EncodedInputStream&); EncodedInputStream& operator=(const EncodedInputStream&); InputByteStream& is_; Ch current_; }; //! Specialized for UTF8 MemoryStream. template <> class EncodedInputStream, MemoryStream> { public: typedef UTF8<>::Ch Ch; EncodedInputStream(MemoryStream& is) : is_(is) { if (static_cast(is_.Peek()) == 0xEFu) is_.Take(); if (static_cast(is_.Peek()) == 0xBBu) is_.Take(); if (static_cast(is_.Peek()) == 0xBFu) is_.Take(); } Ch Peek() const { return is_.Peek(); } Ch Take() { return is_.Take(); } size_t Tell() const { return is_.Tell(); } // Not implemented void Put(Ch) {} void Flush() {} Ch* PutBegin() { return 0; } size_t PutEnd(Ch*) { return 0; } MemoryStream& is_; private: EncodedInputStream(const EncodedInputStream&); EncodedInputStream& operator=(const EncodedInputStream&); }; //! Output byte stream wrapper with statically bound encoding. /*! \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream. */ template class EncodedOutputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); public: typedef typename Encoding::Ch Ch; EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { if (putBOM) Encoding::PutBOM(os_); } void Put(Ch c) { Encoding::Put(os_, c); } void Flush() { os_.Flush(); } // Not implemented Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} Ch Take() { RAPIDJSON_ASSERT(false); return 0;} size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: EncodedOutputStream(const EncodedOutputStream&); EncodedOutputStream& operator=(const EncodedOutputStream&); OutputByteStream& os_; }; #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x //! Input stream wrapper with dynamically bound encoding and automatic encoding detection. /*! \tparam CharType Type of character for reading. \tparam InputByteStream type of input byte stream to be wrapped. */ template class AutoUTFInputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); public: typedef CharType Ch; //! Constructor. /*! \param is input stream to be wrapped. \param type UTF encoding type if it is not detected from the stream. */ AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); DetectType(); static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; takeFunc_ = f[type_]; current_ = takeFunc_(*is_); } UTFType GetType() const { return type_; } bool HasBOM() const { return hasBOM_; } Ch Peek() const { return current_; } Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } size_t Tell() const { return is_->Tell(); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: AutoUTFInputStream(const AutoUTFInputStream&); AutoUTFInputStream& operator=(const AutoUTFInputStream&); // Detect encoding type with BOM or RFC 4627 void DetectType() { // BOM (Byte Order Mark): // 00 00 FE FF UTF-32BE // FF FE 00 00 UTF-32LE // FE FF UTF-16BE // FF FE UTF-16LE // EF BB BF UTF-8 const unsigned char* c = reinterpret_cast(is_->Peek4()); if (!c) return; unsigned bom = static_cast(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); hasBOM_ = false; if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } // RFC 4627: Section 3 // "Since the first two characters of a JSON text will always be ASCII // characters [RFC0020], it is possible to determine whether an octet // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking // at the pattern of nulls in the first four octets." // 00 00 00 xx UTF-32BE // 00 xx 00 xx UTF-16BE // xx 00 00 00 UTF-32LE // xx 00 xx 00 UTF-16LE // xx xx xx xx UTF-8 if (!hasBOM_) { unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); switch (pattern) { case 0x08: type_ = kUTF32BE; break; case 0x0A: type_ = kUTF16BE; break; case 0x01: type_ = kUTF32LE; break; case 0x05: type_ = kUTF16LE; break; case 0x0F: type_ = kUTF8; break; default: break; // Use type defined by user. } } // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); } typedef Ch (*TakeFunc)(InputByteStream& is); InputByteStream* is_; UTFType type_; Ch current_; TakeFunc takeFunc_; bool hasBOM_; }; //! Output stream wrapper with dynamically bound encoding and automatic encoding detection. /*! \tparam CharType Type of character for writing. \tparam OutputByteStream type of output byte stream to be wrapped. */ template class AutoUTFOutputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); public: typedef CharType Ch; //! Constructor. /*! \param os output stream to be wrapped. \param type UTF encoding type. \param putBOM Whether to write BOM at the beginning of the stream. */ AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; putFunc_ = f[type_]; if (putBOM) PutBOM(); } UTFType GetType() const { return type_; } void Put(Ch c) { putFunc_(*os_, c); } void Flush() { os_->Flush(); } // Not implemented Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} Ch Take() { RAPIDJSON_ASSERT(false); return 0;} size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: AutoUTFOutputStream(const AutoUTFOutputStream&); AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); void PutBOM() { typedef void (*PutBOMFunc)(OutputByteStream&); static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; f[type_](*os_); } typedef void (*PutFunc)(OutputByteStream&, Ch); OutputByteStream* os_; UTFType type_; PutFunc putFunc_; }; #undef RAPIDJSON_ENCODINGS_FUNC RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_FILESTREAM_H_ osmium-tool-1.7.1/include/rapidjson/encodings.h000066400000000000000000000676111315004223400215470ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ENCODINGS_H_ #define RAPIDJSON_ENCODINGS_H_ #include "rapidjson.h" #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data RAPIDJSON_DIAG_OFF(4702) // unreachable code #elif defined(__GNUC__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(overflow) #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Encoding /*! \class rapidjson::Encoding \brief Concept for encoding of Unicode characters. \code concept Encoding { typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. enum { supportUnicode = 1 }; // or 0 if not supporting unicode //! \brief Encode a Unicode codepoint to an output stream. //! \param os Output stream. //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. template static void Encode(OutputStream& os, unsigned codepoint); //! \brief Decode a Unicode codepoint from an input stream. //! \param is Input stream. //! \param codepoint Output of the unicode codepoint. //! \return true if a valid codepoint can be decoded from the stream. template static bool Decode(InputStream& is, unsigned* codepoint); //! \brief Validate one Unicode codepoint from an encoded stream. //! \param is Input stream to obtain codepoint. //! \param os Output for copying one codepoint. //! \return true if it is valid. //! \note This function just validating and copying the codepoint without actually decode it. template static bool Validate(InputStream& is, OutputStream& os); // The following functions are deal with byte streams. //! Take a character from input byte stream, skip BOM if exist. template static CharType TakeBOM(InputByteStream& is); //! Take a character from input byte stream. template static Ch Take(InputByteStream& is); //! Put BOM to output byte stream. template static void PutBOM(OutputByteStream& os); //! Put a character to output byte stream. template static void Put(OutputByteStream& os, Ch c); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // UTF8 //! UTF-8 encoding. /*! http://en.wikipedia.org/wiki/UTF-8 http://tools.ietf.org/html/rfc3629 \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. \note implements Encoding concept */ template struct UTF8 { typedef CharType Ch; enum { supportUnicode = 1 }; template static void Encode(OutputStream& os, unsigned codepoint) { if (codepoint <= 0x7F) os.Put(static_cast(codepoint & 0xFF)); else if (codepoint <= 0x7FF) { os.Put(static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); os.Put(static_cast(0x80 | ((codepoint & 0x3F)))); } else if (codepoint <= 0xFFFF) { os.Put(static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); os.Put(static_cast(0x80 | (codepoint & 0x3F))); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); os.Put(static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); os.Put(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); os.Put(static_cast(0x80 | (codepoint & 0x3F))); } } template static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { if (codepoint <= 0x7F) PutUnsafe(os, static_cast(codepoint & 0xFF)); else if (codepoint <= 0x7FF) { PutUnsafe(os, static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); PutUnsafe(os, static_cast(0x80 | ((codepoint & 0x3F)))); } else if (codepoint <= 0xFFFF) { PutUnsafe(os, static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); PutUnsafe(os, static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); PutUnsafe(os, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); } } template static bool Decode(InputStream& is, unsigned* codepoint) { #define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) #define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) #define TAIL() COPY(); TRANS(0x70) typename InputStream::Ch c = is.Take(); if (!(c & 0x80)) { *codepoint = static_cast(c); return true; } unsigned char type = GetRange(static_cast(c)); if (type >= 32) { *codepoint = 0; } else { *codepoint = (0xFF >> type) & static_cast(c); } bool result = true; switch (type) { case 2: TAIL(); return result; case 3: TAIL(); TAIL(); return result; case 4: COPY(); TRANS(0x50); TAIL(); return result; case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; case 6: TAIL(); TAIL(); TAIL(); return result; case 10: COPY(); TRANS(0x20); TAIL(); return result; case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; default: return false; } #undef COPY #undef TRANS #undef TAIL } template static bool Validate(InputStream& is, OutputStream& os) { #define COPY() os.Put(c = is.Take()) #define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) #define TAIL() COPY(); TRANS(0x70) Ch c; COPY(); if (!(c & 0x80)) return true; bool result = true; switch (GetRange(static_cast(c))) { case 2: TAIL(); return result; case 3: TAIL(); TAIL(); return result; case 4: COPY(); TRANS(0x50); TAIL(); return result; case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; case 6: TAIL(); TAIL(); TAIL(); return result; case 10: COPY(); TRANS(0x20); TAIL(); return result; case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; default: return false; } #undef COPY #undef TRANS #undef TAIL } static unsigned char GetRange(unsigned char c) { // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. static const unsigned char type[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, }; return type[c]; } template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); typename InputByteStream::Ch c = Take(is); if (static_cast(c) != 0xEFu) return c; c = is.Take(); if (static_cast(c) != 0xBBu) return c; c = is.Take(); if (static_cast(c) != 0xBFu) return c; c = is.Take(); return c; } template static Ch Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); return static_cast(is.Take()); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(0xEFu)); os.Put(static_cast(0xBBu)); os.Put(static_cast(0xBFu)); } template static void Put(OutputByteStream& os, Ch c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(c)); } }; /////////////////////////////////////////////////////////////////////////////// // UTF16 //! UTF-16 encoding. /*! http://en.wikipedia.org/wiki/UTF-16 http://tools.ietf.org/html/rfc2781 \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. \note implements Encoding concept \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. For streaming, use UTF16LE and UTF16BE, which handle endianness. */ template struct UTF16 { typedef CharType Ch; RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); enum { supportUnicode = 1 }; template static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); if (codepoint <= 0xFFFF) { RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair os.Put(static_cast(codepoint)); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; os.Put(static_cast((v >> 10) | 0xD800)); os.Put((v & 0x3FF) | 0xDC00); } } template static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); if (codepoint <= 0xFFFF) { RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair PutUnsafe(os, static_cast(codepoint)); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; PutUnsafe(os, static_cast((v >> 10) | 0xD800)); PutUnsafe(os, (v & 0x3FF) | 0xDC00); } } template static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); typename InputStream::Ch c = is.Take(); if (c < 0xD800 || c > 0xDFFF) { *codepoint = static_cast(c); return true; } else if (c <= 0xDBFF) { *codepoint = (static_cast(c) & 0x3FF) << 10; c = is.Take(); *codepoint |= (static_cast(c) & 0x3FF); *codepoint += 0x10000; return c >= 0xDC00 && c <= 0xDFFF; } return false; } template static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); typename InputStream::Ch c; os.Put(static_cast(c = is.Take())); if (c < 0xD800 || c > 0xDFFF) return true; else if (c <= 0xDBFF) { os.Put(c = is.Take()); return c >= 0xDC00 && c <= 0xDFFF; } return false; } }; //! UTF-16 little endian encoding. template struct UTF16LE : UTF16 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return static_cast(c) == 0xFEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast(is.Take()); c |= static_cast(static_cast(is.Take())) << 8; return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(0xFFu)); os.Put(static_cast(0xFEu)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(static_cast(c) & 0xFFu)); os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); } }; //! UTF-16 big endian encoding. template struct UTF16BE : UTF16 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return static_cast(c) == 0xFEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast(static_cast(is.Take())) << 8; c |= static_cast(is.Take()); return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(0xFEu)); os.Put(static_cast(0xFFu)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); os.Put(static_cast(static_cast(c) & 0xFFu)); } }; /////////////////////////////////////////////////////////////////////////////// // UTF32 //! UTF-32 encoding. /*! http://en.wikipedia.org/wiki/UTF-32 \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. \note implements Encoding concept \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. For streaming, use UTF32LE and UTF32BE, which handle endianness. */ template struct UTF32 { typedef CharType Ch; RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); enum { supportUnicode = 1 }; template static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); os.Put(codepoint); } template static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); PutUnsafe(os, codepoint); } template static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); Ch c = is.Take(); *codepoint = c; return c <= 0x10FFFF; } template static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); Ch c; os.Put(c = is.Take()); return c <= 0x10FFFF; } }; //! UTF-32 little endian enocoding. template struct UTF32LE : UTF32 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return static_cast(c) == 0x0000FEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast(is.Take()); c |= static_cast(static_cast(is.Take())) << 8; c |= static_cast(static_cast(is.Take())) << 16; c |= static_cast(static_cast(is.Take())) << 24; return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(0xFFu)); os.Put(static_cast(0xFEu)); os.Put(static_cast(0x00u)); os.Put(static_cast(0x00u)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(c & 0xFFu)); os.Put(static_cast((c >> 8) & 0xFFu)); os.Put(static_cast((c >> 16) & 0xFFu)); os.Put(static_cast((c >> 24) & 0xFFu)); } }; //! UTF-32 big endian encoding. template struct UTF32BE : UTF32 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return static_cast(c) == 0x0000FEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast(static_cast(is.Take())) << 24; c |= static_cast(static_cast(is.Take())) << 16; c |= static_cast(static_cast(is.Take())) << 8; c |= static_cast(static_cast(is.Take())); return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(0x00u)); os.Put(static_cast(0x00u)); os.Put(static_cast(0xFEu)); os.Put(static_cast(0xFFu)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast((c >> 24) & 0xFFu)); os.Put(static_cast((c >> 16) & 0xFFu)); os.Put(static_cast((c >> 8) & 0xFFu)); os.Put(static_cast(c & 0xFFu)); } }; /////////////////////////////////////////////////////////////////////////////// // ASCII //! ASCII encoding. /*! http://en.wikipedia.org/wiki/ASCII \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. \note implements Encoding concept */ template struct ASCII { typedef CharType Ch; enum { supportUnicode = 0 }; template static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_ASSERT(codepoint <= 0x7F); os.Put(static_cast(codepoint & 0xFF)); } template static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { RAPIDJSON_ASSERT(codepoint <= 0x7F); PutUnsafe(os, static_cast(codepoint & 0xFF)); } template static bool Decode(InputStream& is, unsigned* codepoint) { uint8_t c = static_cast(is.Take()); *codepoint = c; return c <= 0X7F; } template static bool Validate(InputStream& is, OutputStream& os) { uint8_t c = static_cast(is.Take()); os.Put(static_cast(c)); return c <= 0x7F; } template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); uint8_t c = static_cast(Take(is)); return static_cast(c); } template static Ch Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); return static_cast(is.Take()); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); (void)os; } template static void Put(OutputByteStream& os, Ch c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(c)); } }; /////////////////////////////////////////////////////////////////////////////// // AutoUTF //! Runtime-specified UTF encoding type of a stream. enum UTFType { kUTF8 = 0, //!< UTF-8. kUTF16LE = 1, //!< UTF-16 little endian. kUTF16BE = 2, //!< UTF-16 big endian. kUTF32LE = 3, //!< UTF-32 little endian. kUTF32BE = 4 //!< UTF-32 big endian. }; //! Dynamically select encoding according to stream's runtime-specified UTF encoding type. /*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). */ template struct AutoUTF { typedef CharType Ch; enum { supportUnicode = 1 }; #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x template RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; (*f[os.GetType()])(os, codepoint); } template RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; (*f[os.GetType()])(os, codepoint); } template RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { typedef bool (*DecodeFunc)(InputStream&, unsigned*); static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; return (*f[is.GetType()])(is, codepoint); } template RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { typedef bool (*ValidateFunc)(InputStream&, OutputStream&); static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; return (*f[is.GetType()])(is, os); } #undef RAPIDJSON_ENCODINGS_FUNC }; /////////////////////////////////////////////////////////////////////////////// // Transcoder //! Encoding conversion. template struct Transcoder { //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. template RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; TargetEncoding::Encode(os, codepoint); return true; } template RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; TargetEncoding::EncodeUnsafe(os, codepoint); return true; } //! Validate one Unicode codepoint from an encoded stream. template RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { return Transcode(is, os); // Since source/target encoding is different, must transcode. } }; // Forward declaration. template inline void PutUnsafe(Stream& stream, typename Stream::Ch c); //! Specialization of Transcoder with same source and target encoding. template struct Transcoder { template RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { return Encoding::Validate(is, os); // source/target encoding are the same } }; RAPIDJSON_NAMESPACE_END #if defined(__GNUC__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_ENCODINGS_H_ osmium-tool-1.7.1/include/rapidjson/error/000077500000000000000000000000001315004223400205435ustar00rootroot00000000000000osmium-tool-1.7.1/include/rapidjson/error/en.h000066400000000000000000000074361315004223400213300ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ERROR_EN_H_ #define RAPIDJSON_ERROR_EN_H_ #include "error.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(covered-switch-default) #endif RAPIDJSON_NAMESPACE_BEGIN //! Maps error code of parsing into error message. /*! \ingroup RAPIDJSON_ERRORS \param parseErrorCode Error code obtained in parsing. \return the error message. \note User can make a copy of this function for localization. Using switch-case is safer for future modification of error codes. */ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { switch (parseErrorCode) { case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); default: return RAPIDJSON_ERROR_STRING("Unknown error."); } } RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_ERROR_EN_H_ osmium-tool-1.7.1/include/rapidjson/error/error.h000066400000000000000000000133001315004223400220420ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ERROR_ERROR_H_ #define RAPIDJSON_ERROR_ERROR_H_ #include "../rapidjson.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif /*! \file error.h */ /*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ERROR_CHARTYPE //! Character type of error messages. /*! \ingroup RAPIDJSON_ERRORS The default character type is \c char. On Windows, user can define this macro as \c TCHAR for supporting both unicode/non-unicode settings. */ #ifndef RAPIDJSON_ERROR_CHARTYPE #define RAPIDJSON_ERROR_CHARTYPE char #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ERROR_STRING //! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. /*! \ingroup RAPIDJSON_ERRORS By default this conversion macro does nothing. On Windows, user can define this macro as \c _T(x) for supporting both unicode/non-unicode settings. */ #ifndef RAPIDJSON_ERROR_STRING #define RAPIDJSON_ERROR_STRING(x) x #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // ParseErrorCode //! Error code of parsing. /*! \ingroup RAPIDJSON_ERRORS \see GenericReader::Parse, GenericReader::GetParseErrorCode */ enum ParseErrorCode { kParseErrorNone = 0, //!< No error. kParseErrorDocumentEmpty, //!< The document is empty. kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. kParseErrorValueInvalid, //!< Invalid value. kParseErrorObjectMissName, //!< Missing a name for object member. kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. kParseErrorNumberTooBig, //!< Number too big to be stored in double. kParseErrorNumberMissFraction, //!< Miss fraction part in number. kParseErrorNumberMissExponent, //!< Miss exponent in number. kParseErrorTermination, //!< Parsing was terminated. kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. }; //! Result of parsing (wraps ParseErrorCode) /*! \ingroup RAPIDJSON_ERRORS \code Document doc; ParseResult ok = doc.Parse("[42]"); if (!ok) { fprintf(stderr, "JSON parse error: %s (%u)", GetParseError_En(ok.Code()), ok.Offset()); exit(EXIT_FAILURE); } \endcode \see GenericReader::Parse, GenericDocument::Parse */ struct ParseResult { public: //! Default constructor, no error. ParseResult() : code_(kParseErrorNone), offset_(0) {} //! Constructor to set an error. ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} //! Get the error code. ParseErrorCode Code() const { return code_; } //! Get the error offset, if \ref IsError(), 0 otherwise. size_t Offset() const { return offset_; } //! Conversion to \c bool, returns \c true, iff !\ref IsError(). operator bool() const { return !IsError(); } //! Whether the result is an error. bool IsError() const { return code_ != kParseErrorNone; } bool operator==(const ParseResult& that) const { return code_ == that.code_; } bool operator==(ParseErrorCode code) const { return code_ == code; } friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } //! Reset error code. void Clear() { Set(kParseErrorNone); } //! Update error code and offset. void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } private: ParseErrorCode code_; size_t offset_; }; //! Function pointer type of GetParseError(). /*! \ingroup RAPIDJSON_ERRORS This is the prototype for \c GetParseError_X(), where \c X is a locale. User can dynamically change locale in runtime, e.g.: \code GetParseErrorFunc GetParseError = GetParseError_En; // or whatever const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); \endcode */ typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_ERROR_ERROR_H_ osmium-tool-1.7.1/include/rapidjson/filereadstream.h000066400000000000000000000056541315004223400225640ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_FILEREADSTREAM_H_ #define RAPIDJSON_FILEREADSTREAM_H_ #include "stream.h" #include #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(missing-noreturn) #endif RAPIDJSON_NAMESPACE_BEGIN //! File byte stream for input using fread(). /*! \note implements Stream concept */ class FileReadStream { public: typedef char Ch; //!< Character type (byte). //! Constructor. /*! \param fp File pointer opened for read. \param buffer user-supplied buffer. \param bufferSize size of buffer in bytes. Must >=4 bytes. */ FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { RAPIDJSON_ASSERT(fp_ != 0); RAPIDJSON_ASSERT(bufferSize >= 4); Read(); } Ch Peek() const { return *current_; } Ch Take() { Ch c = *current_; Read(); return c; } size_t Tell() const { return count_ + static_cast(current_ - buffer_); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. const Ch* Peek4() const { return (current_ + 4 <= bufferLast_) ? current_ : 0; } private: void Read() { if (current_ < bufferLast_) ++current_; else if (!eof_) { count_ += readCount_; readCount_ = fread(buffer_, 1, bufferSize_, fp_); bufferLast_ = buffer_ + readCount_ - 1; current_ = buffer_; if (readCount_ < bufferSize_) { buffer_[readCount_] = '\0'; ++bufferLast_; eof_ = true; } } } std::FILE* fp_; Ch *buffer_; size_t bufferSize_; Ch *bufferLast_; Ch *current_; size_t readCount_; size_t count_; //!< Number of characters read bool eof_; }; RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_FILESTREAM_H_ osmium-tool-1.7.1/include/rapidjson/filewritestream.h000066400000000000000000000061031315004223400227710ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_FILEWRITESTREAM_H_ #define RAPIDJSON_FILEWRITESTREAM_H_ #include "stream.h" #include #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(unreachable-code) #endif RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of C file stream for input using fread(). /*! \note implements Stream concept */ class FileWriteStream { public: typedef char Ch; //!< Character type. Only support char. FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { RAPIDJSON_ASSERT(fp_ != 0); } void Put(char c) { if (current_ >= bufferEnd_) Flush(); *current_++ = c; } void PutN(char c, size_t n) { size_t avail = static_cast(bufferEnd_ - current_); while (n > avail) { std::memset(current_, c, avail); current_ += avail; Flush(); n -= avail; avail = static_cast(bufferEnd_ - current_); } if (n > 0) { std::memset(current_, c, n); current_ += n; } } void Flush() { if (current_ != buffer_) { size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); if (result < static_cast(current_ - buffer_)) { // failure deliberately ignored at this time // added to avoid warn_unused_result build errors } current_ = buffer_; } } // Not implemented char Peek() const { RAPIDJSON_ASSERT(false); return 0; } char Take() { RAPIDJSON_ASSERT(false); return 0; } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } private: // Prohibit copy constructor & assignment operator. FileWriteStream(const FileWriteStream&); FileWriteStream& operator=(const FileWriteStream&); std::FILE* fp_; char *buffer_; char *bufferEnd_; char *current_; }; //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(FileWriteStream& stream, char c, size_t n) { stream.PutN(c, n); } RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_FILESTREAM_H_ osmium-tool-1.7.1/include/rapidjson/fwd.h000066400000000000000000000077031315004223400203520ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_FWD_H_ #define RAPIDJSON_FWD_H_ #include "rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN // encodings.h template struct UTF8; template struct UTF16; template struct UTF16BE; template struct UTF16LE; template struct UTF32; template struct UTF32BE; template struct UTF32LE; template struct ASCII; template struct AutoUTF; template struct Transcoder; // allocators.h class CrtAllocator; template class MemoryPoolAllocator; // stream.h template struct GenericStringStream; typedef GenericStringStream > StringStream; template struct GenericInsituStringStream; typedef GenericInsituStringStream > InsituStringStream; // stringbuffer.h template class GenericStringBuffer; typedef GenericStringBuffer, CrtAllocator> StringBuffer; // filereadstream.h class FileReadStream; // filewritestream.h class FileWriteStream; // memorybuffer.h template struct GenericMemoryBuffer; typedef GenericMemoryBuffer MemoryBuffer; // memorystream.h struct MemoryStream; // reader.h template struct BaseReaderHandler; template class GenericReader; typedef GenericReader, UTF8, CrtAllocator> Reader; // writer.h template class Writer; // prettywriter.h template class PrettyWriter; // document.h template struct GenericMember; template class GenericMemberIterator; template struct GenericStringRef; template class GenericValue; typedef GenericValue, MemoryPoolAllocator > Value; template class GenericDocument; typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; // pointer.h template class GenericPointer; typedef GenericPointer Pointer; // schema.h template class IGenericRemoteSchemaDocumentProvider; template class GenericSchemaDocument; typedef GenericSchemaDocument SchemaDocument; typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; template < typename SchemaDocumentType, typename OutputHandler, typename StateAllocator> class GenericSchemaValidator; typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_RAPIDJSONFWD_H_ osmium-tool-1.7.1/include/rapidjson/internal/000077500000000000000000000000001315004223400212265ustar00rootroot00000000000000osmium-tool-1.7.1/include/rapidjson/internal/biginteger.h000066400000000000000000000216631315004223400235260ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_BIGINTEGER_H_ #define RAPIDJSON_BIGINTEGER_H_ #include "../rapidjson.h" #if defined(_MSC_VER) && defined(_M_AMD64) #include // for _umul128 #pragma intrinsic(_umul128) #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { class BigInteger { public: typedef uint64_t Type; BigInteger(const BigInteger& rhs) : count_(rhs.count_) { std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); } explicit BigInteger(uint64_t u) : count_(1) { digits_[0] = u; } BigInteger(const char* decimals, size_t length) : count_(1) { RAPIDJSON_ASSERT(length > 0); digits_[0] = 0; size_t i = 0; const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 while (length >= kMaxDigitPerIteration) { AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); length -= kMaxDigitPerIteration; i += kMaxDigitPerIteration; } if (length > 0) AppendDecimal64(decimals + i, decimals + i + length); } BigInteger& operator=(const BigInteger &rhs) { if (this != &rhs) { count_ = rhs.count_; std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); } return *this; } BigInteger& operator=(uint64_t u) { digits_[0] = u; count_ = 1; return *this; } BigInteger& operator+=(uint64_t u) { Type backup = digits_[0]; digits_[0] += u; for (size_t i = 0; i < count_ - 1; i++) { if (digits_[i] >= backup) return *this; // no carry backup = digits_[i + 1]; digits_[i + 1] += 1; } // Last carry if (digits_[count_ - 1] < backup) PushBack(1); return *this; } BigInteger& operator*=(uint64_t u) { if (u == 0) return *this = 0; if (u == 1) return *this; if (*this == 1) return *this = u; uint64_t k = 0; for (size_t i = 0; i < count_; i++) { uint64_t hi; digits_[i] = MulAdd64(digits_[i], u, k, &hi); k = hi; } if (k > 0) PushBack(k); return *this; } BigInteger& operator*=(uint32_t u) { if (u == 0) return *this = 0; if (u == 1) return *this; if (*this == 1) return *this = u; uint64_t k = 0; for (size_t i = 0; i < count_; i++) { const uint64_t c = digits_[i] >> 32; const uint64_t d = digits_[i] & 0xFFFFFFFF; const uint64_t uc = u * c; const uint64_t ud = u * d; const uint64_t p0 = ud + k; const uint64_t p1 = uc + (p0 >> 32); digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32); k = p1 >> 32; } if (k > 0) PushBack(k); return *this; } BigInteger& operator<<=(size_t shift) { if (IsZero() || shift == 0) return *this; size_t offset = shift / kTypeBit; size_t interShift = shift % kTypeBit; RAPIDJSON_ASSERT(count_ + offset <= kCapacity); if (interShift == 0) { std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type)); count_ += offset; } else { digits_[count_] = 0; for (size_t i = count_; i > 0; i--) digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift)); digits_[offset] = digits_[0] << interShift; count_ += offset; if (digits_[count_]) count_++; } std::memset(digits_, 0, offset * sizeof(Type)); return *this; } bool operator==(const BigInteger& rhs) const { return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; } bool operator==(const Type rhs) const { return count_ == 1 && digits_[0] == rhs; } BigInteger& MultiplyPow5(unsigned exp) { static const uint32_t kPow5[12] = { 5, 5 * 5, 5 * 5 * 5, 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 }; if (exp == 0) return *this; for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 for (; exp >= 13; exp -= 13) *this *= static_cast(1220703125u); // 5^13 if (exp > 0) *this *= kPow5[exp - 1]; return *this; } // Compute absolute difference of this and rhs. // Assume this != rhs bool Difference(const BigInteger& rhs, BigInteger* out) const { int cmp = Compare(rhs); RAPIDJSON_ASSERT(cmp != 0); const BigInteger *a, *b; // Makes a > b bool ret; if (cmp < 0) { a = &rhs; b = this; ret = true; } else { a = this; b = &rhs; ret = false; } Type borrow = 0; for (size_t i = 0; i < a->count_; i++) { Type d = a->digits_[i] - borrow; if (i < b->count_) d -= b->digits_[i]; borrow = (d > a->digits_[i]) ? 1 : 0; out->digits_[i] = d; if (d != 0) out->count_ = i + 1; } return ret; } int Compare(const BigInteger& rhs) const { if (count_ != rhs.count_) return count_ < rhs.count_ ? -1 : 1; for (size_t i = count_; i-- > 0;) if (digits_[i] != rhs.digits_[i]) return digits_[i] < rhs.digits_[i] ? -1 : 1; return 0; } size_t GetCount() const { return count_; } Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; } bool IsZero() const { return count_ == 1 && digits_[0] == 0; } private: void AppendDecimal64(const char* begin, const char* end) { uint64_t u = ParseUint64(begin, end); if (IsZero()) *this = u; else { unsigned exp = static_cast(end - begin); (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u } } void PushBack(Type digit) { RAPIDJSON_ASSERT(count_ < kCapacity); digits_[count_++] = digit; } static uint64_t ParseUint64(const char* begin, const char* end) { uint64_t r = 0; for (const char* p = begin; p != end; ++p) { RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); r = r * 10u + static_cast(*p - '0'); } return r; } // Assume a * b + k < 2^128 static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { #if defined(_MSC_VER) && defined(_M_AMD64) uint64_t low = _umul128(a, b, outHigh) + k; if (low < k) (*outHigh)++; return low; #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) __extension__ typedef unsigned __int128 uint128; uint128 p = static_cast(a) * static_cast(b); p += k; *outHigh = static_cast(p >> 64); return static_cast(p); #else const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; x1 += (x0 >> 32); // can't give carry x1 += x2; if (x1 < x2) x3 += (static_cast(1) << 32); uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); uint64_t hi = x3 + (x1 >> 32); lo += k; if (lo < k) hi++; *outHigh = hi; return lo; #endif } static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 static const size_t kCapacity = kBitCount / sizeof(Type); static const size_t kTypeBit = sizeof(Type) * 8; Type digits_[kCapacity]; size_t count_; }; } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_BIGINTEGER_H_ osmium-tool-1.7.1/include/rapidjson/internal/diyfp.h000066400000000000000000000263701315004223400225220ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. // This is a C++ header-only implementation of Grisu2 algorithm from the publication: // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with // integers." ACM Sigplan Notices 45.6 (2010): 233-243. #ifndef RAPIDJSON_DIYFP_H_ #define RAPIDJSON_DIYFP_H_ #include "../rapidjson.h" #if defined(_MSC_VER) && defined(_M_AMD64) #include #pragma intrinsic(_BitScanReverse64) #pragma intrinsic(_umul128) #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif struct DiyFp { DiyFp() : f(), e() {} DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} explicit DiyFp(double d) { union { double d; uint64_t u64; } u = { d }; int biased_e = static_cast((u.u64 & kDpExponentMask) >> kDpSignificandSize); uint64_t significand = (u.u64 & kDpSignificandMask); if (biased_e != 0) { f = significand + kDpHiddenBit; e = biased_e - kDpExponentBias; } else { f = significand; e = kDpMinExponent + 1; } } DiyFp operator-(const DiyFp& rhs) const { return DiyFp(f - rhs.f, e); } DiyFp operator*(const DiyFp& rhs) const { #if defined(_MSC_VER) && defined(_M_AMD64) uint64_t h; uint64_t l = _umul128(f, rhs.f, &h); if (l & (uint64_t(1) << 63)) // rounding h++; return DiyFp(h, e + rhs.e + 64); #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) __extension__ typedef unsigned __int128 uint128; uint128 p = static_cast(f) * static_cast(rhs.f); uint64_t h = static_cast(p >> 64); uint64_t l = static_cast(p); if (l & (uint64_t(1) << 63)) // rounding h++; return DiyFp(h, e + rhs.e + 64); #else const uint64_t M32 = 0xFFFFFFFF; const uint64_t a = f >> 32; const uint64_t b = f & M32; const uint64_t c = rhs.f >> 32; const uint64_t d = rhs.f & M32; const uint64_t ac = a * c; const uint64_t bc = b * c; const uint64_t ad = a * d; const uint64_t bd = b * d; uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); tmp += 1U << 31; /// mult_round return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); #endif } DiyFp Normalize() const { #if defined(_MSC_VER) && defined(_M_AMD64) unsigned long index; _BitScanReverse64(&index, f); return DiyFp(f << (63 - index), e - (63 - index)); #elif defined(__GNUC__) && __GNUC__ >= 4 int s = __builtin_clzll(f); return DiyFp(f << s, e - s); #else DiyFp res = *this; while (!(res.f & (static_cast(1) << 63))) { res.f <<= 1; res.e--; } return res; #endif } DiyFp NormalizeBoundary() const { DiyFp res = *this; while (!(res.f & (kDpHiddenBit << 1))) { res.f <<= 1; res.e--; } res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); return res; } void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); mi.f <<= mi.e - pl.e; mi.e = pl.e; *plus = pl; *minus = mi; } double ToDouble() const { union { double d; uint64_t u64; }u; const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : static_cast(e + kDpExponentBias); u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); return u.d; } static const int kDiySignificandSize = 64; static const int kDpSignificandSize = 52; static const int kDpExponentBias = 0x3FF + kDpSignificandSize; static const int kDpMaxExponent = 0x7FF - kDpExponentBias; static const int kDpMinExponent = -kDpExponentBias; static const int kDpDenormalExponent = -kDpExponentBias + 1; static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); uint64_t f; int e; }; inline DiyFp GetCachedPowerByIndex(size_t index) { // 10^-348, 10^-340, ..., 10^340 static const uint64_t kCachedPowers_F[] = { RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) }; static const int16_t kCachedPowers_E[] = { -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066 }; return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); } inline DiyFp GetCachedPower(int e, int* K) { //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive int k = static_cast(dk); if (dk - k > 0.0) k++; unsigned index = static_cast((k >> 3) + 1); *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table return GetCachedPowerByIndex(index); } inline DiyFp GetCachedPower10(int exp, int *outExp) { unsigned index = (static_cast(exp) + 348u) / 8u; *outExp = -348 + static_cast(index) * 8; return GetCachedPowerByIndex(index); } #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #ifdef __clang__ RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_OFF(padded) #endif } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_DIYFP_H_ osmium-tool-1.7.1/include/rapidjson/internal/dtoa.h000066400000000000000000000177541315004223400223440ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. // This is a C++ header-only implementation of Grisu2 algorithm from the publication: // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with // integers." ACM Sigplan Notices 45.6 (2010): 233-243. #ifndef RAPIDJSON_DTOA_ #define RAPIDJSON_DTOA_ #include "itoa.h" // GetDigitsLut() #include "diyfp.h" #include "ieee754.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 #endif inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { while (rest < wp_w && delta - rest >= ten_kappa && (rest + ten_kappa < wp_w || /// closer wp_w - rest > rest + ten_kappa - wp_w)) { buffer[len - 1]--; rest += ten_kappa; } } inline unsigned CountDecimalDigit32(uint32_t n) { // Simple pure C++ implementation was faster than __builtin_clz version in this situation. if (n < 10) return 1; if (n < 100) return 2; if (n < 1000) return 3; if (n < 10000) return 4; if (n < 100000) return 5; if (n < 1000000) return 6; if (n < 10000000) return 7; if (n < 100000000) return 8; // Will not reach 10 digits in DigitGen() //if (n < 1000000000) return 9; //return 10; return 9; } inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); const DiyFp wp_w = Mp - W; uint32_t p1 = static_cast(Mp.f >> -one.e); uint64_t p2 = Mp.f & (one.f - 1); unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] *len = 0; while (kappa > 0) { uint32_t d = 0; switch (kappa) { case 9: d = p1 / 100000000; p1 %= 100000000; break; case 8: d = p1 / 10000000; p1 %= 10000000; break; case 7: d = p1 / 1000000; p1 %= 1000000; break; case 6: d = p1 / 100000; p1 %= 100000; break; case 5: d = p1 / 10000; p1 %= 10000; break; case 4: d = p1 / 1000; p1 %= 1000; break; case 3: d = p1 / 100; p1 %= 100; break; case 2: d = p1 / 10; p1 %= 10; break; case 1: d = p1; p1 = 0; break; default:; } if (d || *len) buffer[(*len)++] = static_cast('0' + static_cast(d)); kappa--; uint64_t tmp = (static_cast(p1) << -one.e) + p2; if (tmp <= delta) { *K += kappa; GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); return; } } // kappa = 0 for (;;) { p2 *= 10; delta *= 10; char d = static_cast(p2 >> -one.e); if (d || *len) buffer[(*len)++] = static_cast('0' + d); p2 &= one.f - 1; kappa--; if (p2 < delta) { *K += kappa; int index = -static_cast(kappa); GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast(kappa)] : 0)); return; } } } inline void Grisu2(double value, char* buffer, int* length, int* K) { const DiyFp v(value); DiyFp w_m, w_p; v.NormalizedBoundaries(&w_m, &w_p); const DiyFp c_mk = GetCachedPower(w_p.e, K); const DiyFp W = v.Normalize() * c_mk; DiyFp Wp = w_p * c_mk; DiyFp Wm = w_m * c_mk; Wm.f++; Wp.f--; DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); } inline char* WriteExponent(int K, char* buffer) { if (K < 0) { *buffer++ = '-'; K = -K; } if (K >= 100) { *buffer++ = static_cast('0' + static_cast(K / 100)); K %= 100; const char* d = GetDigitsLut() + K * 2; *buffer++ = d[0]; *buffer++ = d[1]; } else if (K >= 10) { const char* d = GetDigitsLut() + K * 2; *buffer++ = d[0]; *buffer++ = d[1]; } else *buffer++ = static_cast('0' + static_cast(K)); return buffer; } inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { const int kk = length + k; // 10^(kk-1) <= v < 10^kk if (0 <= k && kk <= 21) { // 1234e7 -> 12340000000 for (int i = length; i < kk; i++) buffer[i] = '0'; buffer[kk] = '.'; buffer[kk + 1] = '0'; return &buffer[kk + 2]; } else if (0 < kk && kk <= 21) { // 1234e-2 -> 12.34 std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); buffer[kk] = '.'; if (0 > k + maxDecimalPlaces) { // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 // Remove extra trailing zeros (at least one) after truncation. for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) if (buffer[i] != '0') return &buffer[i + 1]; return &buffer[kk + 2]; // Reserve one zero } else return &buffer[length + 1]; } else if (-6 < kk && kk <= 0) { // 1234e-6 -> 0.001234 const int offset = 2 - kk; std::memmove(&buffer[offset], &buffer[0], static_cast(length)); buffer[0] = '0'; buffer[1] = '.'; for (int i = 2; i < offset; i++) buffer[i] = '0'; if (length - kk > maxDecimalPlaces) { // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 // Remove extra trailing zeros (at least one) after truncation. for (int i = maxDecimalPlaces + 1; i > 2; i--) if (buffer[i] != '0') return &buffer[i + 1]; return &buffer[3]; // Reserve one zero } else return &buffer[length + offset]; } else if (kk < -maxDecimalPlaces) { // Truncate to zero buffer[0] = '0'; buffer[1] = '.'; buffer[2] = '0'; return &buffer[3]; } else if (length == 1) { // 1e30 buffer[1] = 'e'; return WriteExponent(kk - 1, &buffer[2]); } else { // 1234e30 -> 1.234e33 std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); buffer[1] = '.'; buffer[length + 1] = 'e'; return WriteExponent(kk - 1, &buffer[0 + length + 2]); } } inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); Double d(value); if (d.IsZero()) { if (d.Sign()) *buffer++ = '-'; // -0.0, Issue #289 buffer[0] = '0'; buffer[1] = '.'; buffer[2] = '0'; return &buffer[3]; } else { if (value < 0) { *buffer++ = '-'; value = -value; } int length, K; Grisu2(value, buffer, &length, &K); return Prettify(buffer, length, K, maxDecimalPlaces); } } #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_DTOA_ osmium-tool-1.7.1/include/rapidjson/internal/ieee754.h000066400000000000000000000057161315004223400225570ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_IEEE754_ #define RAPIDJSON_IEEE754_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { class Double { public: Double() {} Double(double d) : d_(d) {} Double(uint64_t u) : u_(u) {} double Value() const { return d_; } uint64_t Uint64Value() const { return u_; } double NextPositiveDouble() const { RAPIDJSON_ASSERT(!Sign()); return Double(u_ + 1).Value(); } bool Sign() const { return (u_ & kSignMask) != 0; } uint64_t Significand() const { return u_ & kSignificandMask; } int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } static unsigned EffectiveSignificandSize(int order) { if (order >= -1021) return 53; else if (order <= -1074) return 0; else return static_cast(order) + 1074; } private: static const int kSignificandSize = 52; static const int kExponentBias = 0x3FF; static const int kDenormalExponent = 1 - kExponentBias; static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); union { double d_; uint64_t u_; }; }; } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_IEEE754_ osmium-tool-1.7.1/include/rapidjson/internal/itoa.h000066400000000000000000000241021315004223400223320ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ITOA_ #define RAPIDJSON_ITOA_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { inline const char* GetDigitsLut() { static const char cDigitsLut[200] = { '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' }; return cDigitsLut; } inline char* u32toa(uint32_t value, char* buffer) { const char* cDigitsLut = GetDigitsLut(); if (value < 10000) { const uint32_t d1 = (value / 100) << 1; const uint32_t d2 = (value % 100) << 1; if (value >= 1000) *buffer++ = cDigitsLut[d1]; if (value >= 100) *buffer++ = cDigitsLut[d1 + 1]; if (value >= 10) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; } else if (value < 100000000) { // value = bbbbcccc const uint32_t b = value / 10000; const uint32_t c = value % 10000; const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; if (value >= 10000000) *buffer++ = cDigitsLut[d1]; if (value >= 1000000) *buffer++ = cDigitsLut[d1 + 1]; if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; } else { // value = aabbbbcccc in decimal const uint32_t a = value / 100000000; // 1 to 42 value %= 100000000; if (a >= 10) { const unsigned i = a << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; } else *buffer++ = static_cast('0' + static_cast(a)); const uint32_t b = value / 10000; // 0 to 9999 const uint32_t c = value % 10000; // 0 to 9999 const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; *buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; } return buffer; } inline char* i32toa(int32_t value, char* buffer) { uint32_t u = static_cast(value); if (value < 0) { *buffer++ = '-'; u = ~u + 1; } return u32toa(u, buffer); } inline char* u64toa(uint64_t value, char* buffer) { const char* cDigitsLut = GetDigitsLut(); const uint64_t kTen8 = 100000000; const uint64_t kTen9 = kTen8 * 10; const uint64_t kTen10 = kTen8 * 100; const uint64_t kTen11 = kTen8 * 1000; const uint64_t kTen12 = kTen8 * 10000; const uint64_t kTen13 = kTen8 * 100000; const uint64_t kTen14 = kTen8 * 1000000; const uint64_t kTen15 = kTen8 * 10000000; const uint64_t kTen16 = kTen8 * kTen8; if (value < kTen8) { uint32_t v = static_cast(value); if (v < 10000) { const uint32_t d1 = (v / 100) << 1; const uint32_t d2 = (v % 100) << 1; if (v >= 1000) *buffer++ = cDigitsLut[d1]; if (v >= 100) *buffer++ = cDigitsLut[d1 + 1]; if (v >= 10) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; } else { // value = bbbbcccc const uint32_t b = v / 10000; const uint32_t c = v % 10000; const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; if (value >= 10000000) *buffer++ = cDigitsLut[d1]; if (value >= 1000000) *buffer++ = cDigitsLut[d1 + 1]; if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; } } else if (value < kTen16) { const uint32_t v0 = static_cast(value / kTen8); const uint32_t v1 = static_cast(value % kTen8); const uint32_t b0 = v0 / 10000; const uint32_t c0 = v0 % 10000; const uint32_t d1 = (b0 / 100) << 1; const uint32_t d2 = (b0 % 100) << 1; const uint32_t d3 = (c0 / 100) << 1; const uint32_t d4 = (c0 % 100) << 1; const uint32_t b1 = v1 / 10000; const uint32_t c1 = v1 % 10000; const uint32_t d5 = (b1 / 100) << 1; const uint32_t d6 = (b1 % 100) << 1; const uint32_t d7 = (c1 / 100) << 1; const uint32_t d8 = (c1 % 100) << 1; if (value >= kTen15) *buffer++ = cDigitsLut[d1]; if (value >= kTen14) *buffer++ = cDigitsLut[d1 + 1]; if (value >= kTen13) *buffer++ = cDigitsLut[d2]; if (value >= kTen12) *buffer++ = cDigitsLut[d2 + 1]; if (value >= kTen11) *buffer++ = cDigitsLut[d3]; if (value >= kTen10) *buffer++ = cDigitsLut[d3 + 1]; if (value >= kTen9) *buffer++ = cDigitsLut[d4]; if (value >= kTen8) *buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d6]; *buffer++ = cDigitsLut[d6 + 1]; *buffer++ = cDigitsLut[d7]; *buffer++ = cDigitsLut[d7 + 1]; *buffer++ = cDigitsLut[d8]; *buffer++ = cDigitsLut[d8 + 1]; } else { const uint32_t a = static_cast(value / kTen16); // 1 to 1844 value %= kTen16; if (a < 10) *buffer++ = static_cast('0' + static_cast(a)); else if (a < 100) { const uint32_t i = a << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; } else if (a < 1000) { *buffer++ = static_cast('0' + static_cast(a / 100)); const uint32_t i = (a % 100) << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; } else { const uint32_t i = (a / 100) << 1; const uint32_t j = (a % 100) << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; *buffer++ = cDigitsLut[j]; *buffer++ = cDigitsLut[j + 1]; } const uint32_t v0 = static_cast(value / kTen8); const uint32_t v1 = static_cast(value % kTen8); const uint32_t b0 = v0 / 10000; const uint32_t c0 = v0 % 10000; const uint32_t d1 = (b0 / 100) << 1; const uint32_t d2 = (b0 % 100) << 1; const uint32_t d3 = (c0 / 100) << 1; const uint32_t d4 = (c0 % 100) << 1; const uint32_t b1 = v1 / 10000; const uint32_t c1 = v1 % 10000; const uint32_t d5 = (b1 / 100) << 1; const uint32_t d6 = (b1 % 100) << 1; const uint32_t d7 = (c1 / 100) << 1; const uint32_t d8 = (c1 % 100) << 1; *buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d6]; *buffer++ = cDigitsLut[d6 + 1]; *buffer++ = cDigitsLut[d7]; *buffer++ = cDigitsLut[d7 + 1]; *buffer++ = cDigitsLut[d8]; *buffer++ = cDigitsLut[d8 + 1]; } return buffer; } inline char* i64toa(int64_t value, char* buffer) { uint64_t u = static_cast(value); if (value < 0) { *buffer++ = '-'; u = ~u + 1; } return u64toa(u, buffer); } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ITOA_ osmium-tool-1.7.1/include/rapidjson/internal/meta.h000066400000000000000000000146541315004223400223370ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_INTERNAL_META_H_ #define RAPIDJSON_INTERNAL_META_H_ #include "../rapidjson.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #if defined(_MSC_VER) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(6334) #endif #if RAPIDJSON_HAS_CXX11_TYPETRAITS #include #endif //@cond RAPIDJSON_INTERNAL RAPIDJSON_NAMESPACE_BEGIN namespace internal { // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching template struct Void { typedef void Type; }; /////////////////////////////////////////////////////////////////////////////// // BoolType, TrueType, FalseType // template struct BoolType { static const bool Value = Cond; typedef BoolType Type; }; typedef BoolType TrueType; typedef BoolType FalseType; /////////////////////////////////////////////////////////////////////////////// // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr // template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; template struct SelectIfCond : SelectIfImpl::template Apply {}; template struct SelectIf : SelectIfCond {}; template struct AndExprCond : FalseType {}; template <> struct AndExprCond : TrueType {}; template struct OrExprCond : TrueType {}; template <> struct OrExprCond : FalseType {}; template struct BoolExpr : SelectIf::Type {}; template struct NotExpr : SelectIf::Type {}; template struct AndExpr : AndExprCond::Type {}; template struct OrExpr : OrExprCond::Type {}; /////////////////////////////////////////////////////////////////////////////// // AddConst, MaybeAddConst, RemoveConst template struct AddConst { typedef const T Type; }; template struct MaybeAddConst : SelectIfCond {}; template struct RemoveConst { typedef T Type; }; template struct RemoveConst { typedef T Type; }; /////////////////////////////////////////////////////////////////////////////// // IsSame, IsConst, IsMoreConst, IsPointer // template struct IsSame : FalseType {}; template struct IsSame : TrueType {}; template struct IsConst : FalseType {}; template struct IsConst : TrueType {}; template struct IsMoreConst : AndExpr::Type, typename RemoveConst::Type>, BoolType::Value >= IsConst::Value> >::Type {}; template struct IsPointer : FalseType {}; template struct IsPointer : TrueType {}; /////////////////////////////////////////////////////////////////////////////// // IsBaseOf // #if RAPIDJSON_HAS_CXX11_TYPETRAITS template struct IsBaseOf : BoolType< ::std::is_base_of::value> {}; #else // simplified version adopted from Boost template struct IsBaseOfImpl { RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); typedef char (&Yes)[1]; typedef char (&No) [2]; template static Yes Check(const D*, T); static No Check(const B*, int); struct Host { operator const B*() const; operator const D*(); }; enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; }; template struct IsBaseOf : OrExpr, BoolExpr > >::Type {}; #endif // RAPIDJSON_HAS_CXX11_TYPETRAITS ////////////////////////////////////////////////////////////////////////// // EnableIf / DisableIf // template struct EnableIfCond { typedef T Type; }; template struct EnableIfCond { /* empty */ }; template struct DisableIfCond { typedef T Type; }; template struct DisableIfCond { /* empty */ }; template struct EnableIf : EnableIfCond {}; template struct DisableIf : DisableIfCond {}; // SFINAE helpers struct SfinaeTag {}; template struct RemoveSfinaeTag; template struct RemoveSfinaeTag { typedef T Type; }; #define RAPIDJSON_REMOVEFPTR_(type) \ typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type #define RAPIDJSON_ENABLEIF(cond) \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ ::Type * = NULL #define RAPIDJSON_DISABLEIF(cond) \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ ::Type * = NULL #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ ::Type #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ ::Type } // namespace internal RAPIDJSON_NAMESPACE_END //@endcond #if defined(__GNUC__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_INTERNAL_META_H_ osmium-tool-1.7.1/include/rapidjson/internal/pow10.h000066400000000000000000000070131315004223400223460ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_POW10_ #define RAPIDJSON_POW10_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Computes integer powers of 10 in double (10.0^n). /*! This function uses lookup table for fast and accurate results. \param n non-negative exponent. Must <= 308. \return 10.0^n */ inline double Pow10(int n) { static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 }; RAPIDJSON_ASSERT(n >= 0 && n <= 308); return e[n]; } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_POW10_ osmium-tool-1.7.1/include/rapidjson/internal/regex.h000066400000000000000000000603711315004223400225200ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_INTERNAL_REGEX_H_ #define RAPIDJSON_INTERNAL_REGEX_H_ #include "../allocators.h" #include "../stream.h" #include "stack.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(implicit-fallthrough) #endif #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif #ifndef RAPIDJSON_REGEX_VERBOSE #define RAPIDJSON_REGEX_VERBOSE 0 #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { /////////////////////////////////////////////////////////////////////////////// // GenericRegex static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 static const SizeType kRegexInvalidRange = ~SizeType(0); //! Regular expression engine with subset of ECMAscript grammar. /*! Supported regular expression syntax: - \c ab Concatenation - \c a|b Alternation - \c a? Zero or one - \c a* Zero or more - \c a+ One or more - \c a{3} Exactly 3 times - \c a{3,} At least 3 times - \c a{3,5} 3 to 5 times - \c (ab) Grouping - \c ^a At the beginning - \c a$ At the end - \c . Any character - \c [abc] Character classes - \c [a-c] Character class range - \c [a-z0-9_] Character class combination - \c [^abc] Negated character classes - \c [^a-c] Negated character class range - \c [\b] Backspace (U+0008) - \c \\| \\\\ ... Escape characters - \c \\f Form feed (U+000C) - \c \\n Line feed (U+000A) - \c \\r Carriage return (U+000D) - \c \\t Tab (U+0009) - \c \\v Vertical tab (U+000B) \note This is a Thompson NFA engine, implemented with reference to Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", https://swtch.com/~rsc/regexp/regexp1.html */ template class GenericRegex { public: typedef typename Encoding::Ch Ch; GenericRegex(const Ch* source, Allocator* allocator = 0) : states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_() { GenericStringStream ss(source); DecodedStream > ds(ss); Parse(ds); } ~GenericRegex() { Allocator::Free(stateSet_); } bool IsValid() const { return root_ != kRegexInvalidState; } template bool Match(InputStream& is) const { return SearchWithAnchoring(is, true, true); } bool Match(const Ch* s) const { GenericStringStream is(s); return Match(is); } template bool Search(InputStream& is) const { return SearchWithAnchoring(is, anchorBegin_, anchorEnd_); } bool Search(const Ch* s) const { GenericStringStream is(s); return Search(is); } private: enum Operator { kZeroOrOne, kZeroOrMore, kOneOrMore, kConcatenation, kAlternation, kLeftParenthesis }; static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.' static const unsigned kRangeCharacterClass = 0xFFFFFFFE; static const unsigned kRangeNegationFlag = 0x80000000; struct Range { unsigned start; // unsigned end; SizeType next; }; struct State { SizeType out; //!< Equals to kInvalid for matching state SizeType out1; //!< Equals to non-kInvalid for split SizeType rangeStart; unsigned codepoint; }; struct Frag { Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {} SizeType start; SizeType out; //!< link-list of all output states SizeType minIndex; }; template class DecodedStream { public: DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } unsigned Peek() { return codepoint_; } unsigned Take() { unsigned c = codepoint_; if (c) // No further decoding when '\0' Decode(); return c; } private: void Decode() { if (!Encoding::Decode(ss_, &codepoint_)) codepoint_ = 0; } SourceStream& ss_; unsigned codepoint_; }; State& GetState(SizeType index) { RAPIDJSON_ASSERT(index < stateCount_); return states_.template Bottom()[index]; } const State& GetState(SizeType index) const { RAPIDJSON_ASSERT(index < stateCount_); return states_.template Bottom()[index]; } Range& GetRange(SizeType index) { RAPIDJSON_ASSERT(index < rangeCount_); return ranges_.template Bottom()[index]; } const Range& GetRange(SizeType index) const { RAPIDJSON_ASSERT(index < rangeCount_); return ranges_.template Bottom()[index]; } template void Parse(DecodedStream& ds) { Allocator allocator; Stack operandStack(&allocator, 256); // Frag Stack operatorStack(&allocator, 256); // Operator Stack atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis) *atomCountStack.template Push() = 0; unsigned codepoint; while (ds.Peek() != 0) { switch (codepoint = ds.Take()) { case '^': anchorBegin_ = true; break; case '$': anchorEnd_ = true; break; case '|': while (!operatorStack.Empty() && *operatorStack.template Top() < kAlternation) if (!Eval(operandStack, *operatorStack.template Pop(1))) return; *operatorStack.template Push() = kAlternation; *atomCountStack.template Top() = 0; break; case '(': *operatorStack.template Push() = kLeftParenthesis; *atomCountStack.template Push() = 0; break; case ')': while (!operatorStack.Empty() && *operatorStack.template Top() != kLeftParenthesis) if (!Eval(operandStack, *operatorStack.template Pop(1))) return; if (operatorStack.Empty()) return; operatorStack.template Pop(1); atomCountStack.template Pop(1); ImplicitConcatenation(atomCountStack, operatorStack); break; case '?': if (!Eval(operandStack, kZeroOrOne)) return; break; case '*': if (!Eval(operandStack, kZeroOrMore)) return; break; case '+': if (!Eval(operandStack, kOneOrMore)) return; break; case '{': { unsigned n, m; if (!ParseUnsigned(ds, &n)) return; if (ds.Peek() == ',') { ds.Take(); if (ds.Peek() == '}') m = kInfinityQuantifier; else if (!ParseUnsigned(ds, &m) || m < n) return; } else m = n; if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}') return; ds.Take(); } break; case '.': PushOperand(operandStack, kAnyCharacterClass); ImplicitConcatenation(atomCountStack, operatorStack); break; case '[': { SizeType range; if (!ParseRange(ds, &range)) return; SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass); GetState(s).rangeStart = range; *operandStack.template Push() = Frag(s, s, s); } ImplicitConcatenation(atomCountStack, operatorStack); break; case '\\': // Escape character if (!CharacterEscape(ds, &codepoint)) return; // Unsupported escape character // fall through to default default: // Pattern character PushOperand(operandStack, codepoint); ImplicitConcatenation(atomCountStack, operatorStack); } } while (!operatorStack.Empty()) if (!Eval(operandStack, *operatorStack.template Pop(1))) return; // Link the operand to matching state. if (operandStack.GetSize() == sizeof(Frag)) { Frag* e = operandStack.template Pop(1); Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0)); root_ = e->start; #if RAPIDJSON_REGEX_VERBOSE printf("root: %d\n", root_); for (SizeType i = 0; i < stateCount_ ; i++) { State& s = GetState(i); printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint); } printf("\n"); #endif } // Preallocate buffer for SearchWithAnchoring() RAPIDJSON_ASSERT(stateSet_ == 0); if (stateCount_ > 0) { stateSet_ = static_cast(states_.GetAllocator().Malloc(GetStateSetSize())); state0_.template Reserve(stateCount_); state1_.template Reserve(stateCount_); } } SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { State* s = states_.template Push(); s->out = out; s->out1 = out1; s->codepoint = codepoint; s->rangeStart = kRegexInvalidRange; return stateCount_++; } void PushOperand(Stack& operandStack, unsigned codepoint) { SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint); *operandStack.template Push() = Frag(s, s, s); } void ImplicitConcatenation(Stack& atomCountStack, Stack& operatorStack) { if (*atomCountStack.template Top()) *operatorStack.template Push() = kConcatenation; (*atomCountStack.template Top())++; } SizeType Append(SizeType l1, SizeType l2) { SizeType old = l1; while (GetState(l1).out != kRegexInvalidState) l1 = GetState(l1).out; GetState(l1).out = l2; return old; } void Patch(SizeType l, SizeType s) { for (SizeType next; l != kRegexInvalidState; l = next) { next = GetState(l).out; GetState(l).out = s; } } bool Eval(Stack& operandStack, Operator op) { switch (op) { case kConcatenation: RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); { Frag e2 = *operandStack.template Pop(1); Frag e1 = *operandStack.template Pop(1); Patch(e1.out, e2.start); *operandStack.template Push() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex)); } return true; case kAlternation: if (operandStack.GetSize() >= sizeof(Frag) * 2) { Frag e2 = *operandStack.template Pop(1); Frag e1 = *operandStack.template Pop(1); SizeType s = NewState(e1.start, e2.start, 0); *operandStack.template Push() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex)); return true; } return false; case kZeroOrOne: if (operandStack.GetSize() >= sizeof(Frag)) { Frag e = *operandStack.template Pop(1); SizeType s = NewState(kRegexInvalidState, e.start, 0); *operandStack.template Push() = Frag(s, Append(e.out, s), e.minIndex); return true; } return false; case kZeroOrMore: if (operandStack.GetSize() >= sizeof(Frag)) { Frag e = *operandStack.template Pop(1); SizeType s = NewState(kRegexInvalidState, e.start, 0); Patch(e.out, s); *operandStack.template Push() = Frag(s, s, e.minIndex); return true; } return false; default: RAPIDJSON_ASSERT(op == kOneOrMore); if (operandStack.GetSize() >= sizeof(Frag)) { Frag e = *operandStack.template Pop(1); SizeType s = NewState(kRegexInvalidState, e.start, 0); Patch(e.out, s); *operandStack.template Push() = Frag(e.start, s, e.minIndex); return true; } return false; } } bool EvalQuantifier(Stack& operandStack, unsigned n, unsigned m) { RAPIDJSON_ASSERT(n <= m); RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); if (n == 0) { if (m == 0) // a{0} not support return false; else if (m == kInfinityQuantifier) Eval(operandStack, kZeroOrMore); // a{0,} -> a* else { Eval(operandStack, kZeroOrOne); // a{0,5} -> a? for (unsigned i = 0; i < m - 1; i++) CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a? for (unsigned i = 0; i < m - 1; i++) Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a? } return true; } for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a CloneTopOperand(operandStack); if (m == kInfinityQuantifier) Eval(operandStack, kOneOrMore); // a{3,} -> a a a+ else if (m > n) { CloneTopOperand(operandStack); // a{3,5} -> a a a a Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a? for (unsigned i = n; i < m - 1; i++) CloneTopOperand(operandStack); // a{3,5} -> a a a a? a? for (unsigned i = n; i < m; i++) Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a? } for (unsigned i = 0; i < n - 1; i++) Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a? return true; } static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; } void CloneTopOperand(Stack& operandStack) { const Frag src = *operandStack.template Top(); // Copy constructor to prevent invalidation SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_) State* s = states_.template Push(count); memcpy(s, &GetState(src.minIndex), count * sizeof(State)); for (SizeType j = 0; j < count; j++) { if (s[j].out != kRegexInvalidState) s[j].out += count; if (s[j].out1 != kRegexInvalidState) s[j].out1 += count; } *operandStack.template Push() = Frag(src.start + count, src.out + count, src.minIndex + count); stateCount_ += count; } template bool ParseUnsigned(DecodedStream& ds, unsigned* u) { unsigned r = 0; if (ds.Peek() < '0' || ds.Peek() > '9') return false; while (ds.Peek() >= '0' && ds.Peek() <= '9') { if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 return false; // overflow r = r * 10 + (ds.Take() - '0'); } *u = r; return true; } template bool ParseRange(DecodedStream& ds, SizeType* range) { bool isBegin = true; bool negate = false; int step = 0; SizeType start = kRegexInvalidRange; SizeType current = kRegexInvalidRange; unsigned codepoint; while ((codepoint = ds.Take()) != 0) { if (isBegin) { isBegin = false; if (codepoint == '^') { negate = true; continue; } } switch (codepoint) { case ']': if (start == kRegexInvalidRange) return false; // Error: nothing inside [] if (step == 2) { // Add trailing '-' SizeType r = NewRange('-'); RAPIDJSON_ASSERT(current != kRegexInvalidRange); GetRange(current).next = r; } if (negate) GetRange(start).start |= kRangeNegationFlag; *range = start; return true; case '\\': if (ds.Peek() == 'b') { ds.Take(); codepoint = 0x0008; // Escape backspace character } else if (!CharacterEscape(ds, &codepoint)) return false; // fall through to default default: switch (step) { case 1: if (codepoint == '-') { step++; break; } // fall through to step 0 for other characters case 0: { SizeType r = NewRange(codepoint); if (current != kRegexInvalidRange) GetRange(current).next = r; if (start == kRegexInvalidRange) start = r; current = r; } step = 1; break; default: RAPIDJSON_ASSERT(step == 2); GetRange(current).end = codepoint; step = 0; } } } return false; } SizeType NewRange(unsigned codepoint) { Range* r = ranges_.template Push(); r->start = r->end = codepoint; r->next = kRegexInvalidRange; return rangeCount_++; } template bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { unsigned codepoint; switch (codepoint = ds.Take()) { case '^': case '$': case '|': case '(': case ')': case '?': case '*': case '+': case '.': case '[': case ']': case '{': case '}': case '\\': *escapedCodepoint = codepoint; return true; case 'f': *escapedCodepoint = 0x000C; return true; case 'n': *escapedCodepoint = 0x000A; return true; case 'r': *escapedCodepoint = 0x000D; return true; case 't': *escapedCodepoint = 0x0009; return true; case 'v': *escapedCodepoint = 0x000B; return true; default: return false; // Unsupported escape character } } template bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const { RAPIDJSON_ASSERT(IsValid()); DecodedStream ds(is); state0_.Clear(); Stack *current = &state0_, *next = &state1_; const size_t stateSetSize = GetStateSetSize(); std::memset(stateSet_, 0, stateSetSize); bool matched = AddState(*current, root_); unsigned codepoint; while (!current->Empty() && (codepoint = ds.Take()) != 0) { std::memset(stateSet_, 0, stateSetSize); next->Clear(); matched = false; for (const SizeType* s = current->template Bottom(); s != current->template End(); ++s) { const State& sr = GetState(*s); if (sr.codepoint == codepoint || sr.codepoint == kAnyCharacterClass || (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) { matched = AddState(*next, sr.out) || matched; if (!anchorEnd && matched) return true; } if (!anchorBegin) AddState(*next, root_); } internal::Swap(current, next); } return matched; } size_t GetStateSetSize() const { return (stateCount_ + 31) / 32 * 4; } // Return whether the added states is a match state bool AddState(Stack& l, SizeType index) const { RAPIDJSON_ASSERT(index != kRegexInvalidState); const State& s = GetState(index); if (s.out1 != kRegexInvalidState) { // Split bool matched = AddState(l, s.out); return AddState(l, s.out1) || matched; } else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) { stateSet_[index >> 5] |= (1 << (index & 31)); *l.template PushUnsafe() = index; } return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. } bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0; while (rangeIndex != kRegexInvalidRange) { const Range& r = GetRange(rangeIndex); if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end) return yes; rangeIndex = r.next; } return !yes; } Stack states_; Stack ranges_; SizeType root_; SizeType stateCount_; SizeType rangeCount_; static const unsigned kInfinityQuantifier = ~0u; // For SearchWithAnchoring() uint32_t* stateSet_; // allocated by states_.GetAllocator() mutable Stack state0_; mutable Stack state1_; bool anchorBegin_; bool anchorEnd_; }; typedef GenericRegex > Regex; } // namespace internal RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #ifdef _MSC_VER RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_INTERNAL_REGEX_H_ osmium-tool-1.7.1/include/rapidjson/internal/stack.h000066400000000000000000000155621315004223400225150ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_ #include "../allocators.h" #include "swap.h" #if defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(c++98-compat) #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { /////////////////////////////////////////////////////////////////////////////// // Stack //! A type-unsafe stack for storing different types of data. /*! \tparam Allocator Allocator for allocating stack memory. */ template class Stack { public: // Optimization note: Do not allocate memory for stack_ in constructor. // Do it lazily when first Push() -> Expand() -> Resize(). Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS Stack(Stack&& rhs) : allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), stack_(rhs.stack_), stackTop_(rhs.stackTop_), stackEnd_(rhs.stackEnd_), initialCapacity_(rhs.initialCapacity_) { rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.stack_ = 0; rhs.stackTop_ = 0; rhs.stackEnd_ = 0; rhs.initialCapacity_ = 0; } #endif ~Stack() { Destroy(); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS Stack& operator=(Stack&& rhs) { if (&rhs != this) { Destroy(); allocator_ = rhs.allocator_; ownAllocator_ = rhs.ownAllocator_; stack_ = rhs.stack_; stackTop_ = rhs.stackTop_; stackEnd_ = rhs.stackEnd_; initialCapacity_ = rhs.initialCapacity_; rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.stack_ = 0; rhs.stackTop_ = 0; rhs.stackEnd_ = 0; rhs.initialCapacity_ = 0; } return *this; } #endif void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { internal::Swap(allocator_, rhs.allocator_); internal::Swap(ownAllocator_, rhs.ownAllocator_); internal::Swap(stack_, rhs.stack_); internal::Swap(stackTop_, rhs.stackTop_); internal::Swap(stackEnd_, rhs.stackEnd_); internal::Swap(initialCapacity_, rhs.initialCapacity_); } void Clear() { stackTop_ = stack_; } void ShrinkToFit() { if (Empty()) { // If the stack is empty, completely deallocate the memory. Allocator::Free(stack_); stack_ = 0; stackTop_ = 0; stackEnd_ = 0; } else Resize(GetSize()); } // Optimization note: try to minimize the size of this function for force inline. // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. template RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { // Expand the stack if needed if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) Expand(count); } template RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { Reserve(count); return PushUnsafe(count); } template RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); T* ret = reinterpret_cast(stackTop_); stackTop_ += sizeof(T) * count; return ret; } template T* Pop(size_t count) { RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); stackTop_ -= count * sizeof(T); return reinterpret_cast(stackTop_); } template T* Top() { RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); return reinterpret_cast(stackTop_ - sizeof(T)); } template const T* Top() const { RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); return reinterpret_cast(stackTop_ - sizeof(T)); } template T* End() { return reinterpret_cast(stackTop_); } template const T* End() const { return reinterpret_cast(stackTop_); } template T* Bottom() { return reinterpret_cast(stack_); } template const T* Bottom() const { return reinterpret_cast(stack_); } bool HasAllocator() const { return allocator_ != 0; } Allocator& GetAllocator() { RAPIDJSON_ASSERT(allocator_); return *allocator_; } bool Empty() const { return stackTop_ == stack_; } size_t GetSize() const { return static_cast(stackTop_ - stack_); } size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } private: template void Expand(size_t count) { // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. size_t newCapacity; if (stack_ == 0) { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); newCapacity = initialCapacity_; } else { newCapacity = GetCapacity(); newCapacity += (newCapacity + 1) / 2; } size_t newSize = GetSize() + sizeof(T) * count; if (newCapacity < newSize) newCapacity = newSize; Resize(newCapacity); } void Resize(size_t newCapacity) { const size_t size = GetSize(); // Backup the current size stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); stackTop_ = stack_ + size; stackEnd_ = stack_ + newCapacity; } void Destroy() { Allocator::Free(stack_); RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack } // Prohibit copy constructor & assignment operator. Stack(const Stack&); Stack& operator=(const Stack&); Allocator* allocator_; Allocator* ownAllocator_; char *stack_; char *stackTop_; char *stackEnd_; size_t initialCapacity_; }; } // namespace internal RAPIDJSON_NAMESPACE_END #if defined(__clang__) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_STACK_H_ osmium-tool-1.7.1/include/rapidjson/internal/strfunc.h000066400000000000000000000035511315004223400230670ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ #define RAPIDJSON_INTERNAL_STRFUNC_H_ #include "../stream.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Custom strlen() which works on different character types. /*! \tparam Ch Character type (e.g. char, wchar_t, short) \param s Null-terminated input string. \return Number of characters in the string. \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. */ template inline SizeType StrLen(const Ch* s) { const Ch* p = s; while (*p) ++p; return SizeType(p - s); } //! Returns number of code points in a encoded string. template bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { GenericStringStream is(s); const typename Encoding::Ch* end = s + length; SizeType count = 0; while (is.src_ < end) { unsigned codepoint; if (!Encoding::Decode(is, &codepoint)) return false; count++; } *outCount = count; return true; } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ osmium-tool-1.7.1/include/rapidjson/internal/strtod.h000066400000000000000000000207401315004223400227210ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_STRTOD_ #define RAPIDJSON_STRTOD_ #include "ieee754.h" #include "biginteger.h" #include "diyfp.h" #include "pow10.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { inline double FastPath(double significand, int exp) { if (exp < -308) return 0.0; else if (exp >= 0) return significand * internal::Pow10(exp); else return significand / internal::Pow10(-exp); } inline double StrtodNormalPrecision(double d, int p) { if (p < -308) { // Prevent expSum < -308, making Pow10(p) = 0 d = FastPath(d, -308); d = FastPath(d, p + 308); } else d = FastPath(d, p); return d; } template inline T Min3(T a, T b, T c) { T m = a; if (m > b) m = b; if (m > c) m = c; return m; } inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { const Double db(b); const uint64_t bInt = db.IntegerSignificand(); const int bExp = db.IntegerExponent(); const int hExp = bExp - 1; int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; // Adjust for decimal exponent if (dExp >= 0) { dS_Exp2 += dExp; dS_Exp5 += dExp; } else { bS_Exp2 -= dExp; bS_Exp5 -= dExp; hS_Exp2 -= dExp; hS_Exp5 -= dExp; } // Adjust for binary exponent if (bExp >= 0) bS_Exp2 += bExp; else { dS_Exp2 -= bExp; hS_Exp2 -= bExp; } // Adjust for half ulp exponent if (hExp >= 0) hS_Exp2 += hExp; else { dS_Exp2 -= hExp; bS_Exp2 -= hExp; } // Remove common power of two factor from all three scaled values int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); dS_Exp2 -= common_Exp2; bS_Exp2 -= common_Exp2; hS_Exp2 -= common_Exp2; BigInteger dS = d; dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); BigInteger bS(bInt); bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); BigInteger hS(1); hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); BigInteger delta(0); dS.Difference(bS, &delta); return delta.Compare(hS); } inline bool StrtodFast(double d, int p, double* result) { // Use fast path for string-to-double conversion if possible // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ if (p > 22 && p < 22 + 16) { // Fast Path Cases In Disguise d *= internal::Pow10(p - 22); p = 22; } if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 *result = FastPath(d, p); return true; } else return false; } // Compute an approximation and see if it is within 1/2 ULP inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { uint64_t significand = 0; size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 for (; i < length; i++) { if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) break; significand = significand * 10u + static_cast(decimals[i] - '0'); } if (i < length && decimals[i] >= '5') // Rounding significand++; size_t remaining = length - i; const unsigned kUlpShift = 3; const unsigned kUlp = 1 << kUlpShift; int64_t error = (remaining == 0) ? 0 : kUlp / 2; DiyFp v(significand, 0); v = v.Normalize(); error <<= -v.e; const int dExp = static_cast(decimalPosition) - static_cast(i) + exp; int actualExp; DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); if (actualExp != dExp) { static const DiyFp kPow10[] = { DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 }; int adjustment = dExp - actualExp - 1; RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); v = v * kPow10[adjustment]; if (length + static_cast(adjustment)> 19u) // has more digits than decimal digits in 64-bit error += kUlp / 2; } v = v * cachedPower; error += kUlp + (error == 0 ? 0 : 1); const int oldExp = v.e; v = v.Normalize(); error <<= oldExp - v.e; const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); unsigned precisionSize = 64 - effectiveSignificandSize; if (precisionSize + kUlpShift >= 64) { unsigned scaleExp = (precisionSize + kUlpShift) - 63; v.f >>= scaleExp; v.e += scaleExp; error = (error >> scaleExp) + 1 + static_cast(kUlp); precisionSize -= scaleExp; } DiyFp rounded(v.f >> precisionSize, v.e + static_cast(precisionSize)); const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; if (precisionBits >= halfWay + static_cast(error)) { rounded.f++; if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) rounded.f >>= 1; rounded.e++; } } *result = rounded.ToDouble(); return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); } inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { const BigInteger dInt(decimals, length); const int dExp = static_cast(decimalPosition) - static_cast(length) + exp; Double a(approx); int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); if (cmp < 0) return a.Value(); // within half ULP else if (cmp == 0) { // Round towards even if (a.Significand() & 1) return a.NextPositiveDouble(); else return a.Value(); } else // adjustment return a.NextPositiveDouble(); } inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { RAPIDJSON_ASSERT(d >= 0.0); RAPIDJSON_ASSERT(length >= 1); double result; if (StrtodFast(d, p, &result)) return result; // Trim leading zeros while (*decimals == '0' && length > 1) { length--; decimals++; decimalPosition--; } // Trim trailing zeros while (decimals[length - 1] == '0' && length > 1) { length--; decimalPosition--; exp++; } // Trim right-most digits const int kMaxDecimalDigit = 780; if (static_cast(length) > kMaxDecimalDigit) { int delta = (static_cast(length) - kMaxDecimalDigit); exp += delta; decimalPosition -= static_cast(delta); length = kMaxDecimalDigit; } // If too small, underflow to zero if (int(length) + exp < -324) return 0.0; if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) return result; // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison return StrtodBigInteger(result, decimals, length, decimalPosition, exp); } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_STRTOD_ osmium-tool-1.7.1/include/rapidjson/internal/swap.h000066400000000000000000000026131315004223400223530ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_INTERNAL_SWAP_H_ #define RAPIDJSON_INTERNAL_SWAP_H_ #include "../rapidjson.h" #if defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(c++98-compat) #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Custom swap() to avoid dependency on C++ header /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. \note This has the same semantics as std::swap(). */ template inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { T tmp = a; a = b; b = tmp; } } // namespace internal RAPIDJSON_NAMESPACE_END #if defined(__clang__) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_INTERNAL_SWAP_H_ osmium-tool-1.7.1/include/rapidjson/istreamwrapper.h000066400000000000000000000067701315004223400226420ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ISTREAMWRAPPER_H_ #define RAPIDJSON_ISTREAMWRAPPER_H_ #include "stream.h" #include #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized #endif RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. /*! The classes can be wrapped including but not limited to: - \c std::istringstream - \c std::stringstream - \c std::wistringstream - \c std::wstringstream - \c std::ifstream - \c std::fstream - \c std::wifstream - \c std::wfstream \tparam StreamType Class derived from \c std::basic_istream. */ template class BasicIStreamWrapper { public: typedef typename StreamType::char_type Ch; BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} Ch Peek() const { typename StreamType::int_type c = stream_.peek(); return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : '\0'; } Ch Take() { typename StreamType::int_type c = stream_.get(); if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { count_++; return static_cast(c); } else return '\0'; } // tellg() may return -1 when failed. So we count by ourself. size_t Tell() const { return count_; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. const Ch* Peek4() const { RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. int i; bool hasError = false; for (i = 0; i < 4; ++i) { typename StreamType::int_type c = stream_.get(); if (c == StreamType::traits_type::eof()) { hasError = true; stream_.clear(); break; } peekBuffer_[i] = static_cast(c); } for (--i; i >= 0; --i) stream_.putback(peekBuffer_[i]); return !hasError ? peekBuffer_ : 0; } private: BasicIStreamWrapper(const BasicIStreamWrapper&); BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); StreamType& stream_; size_t count_; //!< Number of characters read. Note: mutable Ch peekBuffer_[4]; }; typedef BasicIStreamWrapper IStreamWrapper; typedef BasicIStreamWrapper WIStreamWrapper; #if defined(__clang__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ISTREAMWRAPPER_H_ osmium-tool-1.7.1/include/rapidjson/memorybuffer.h000066400000000000000000000050001315004223400222600ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_MEMORYBUFFER_H_ #define RAPIDJSON_MEMORYBUFFER_H_ #include "stream.h" #include "internal/stack.h" RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory output byte stream. /*! This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. Differences between MemoryBuffer and StringBuffer: 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. \tparam Allocator type for allocating memory buffer. \note implements Stream concept */ template struct GenericMemoryBuffer { typedef char Ch; // byte GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} void Put(Ch c) { *stack_.template Push() = c; } void Flush() {} void Clear() { stack_.Clear(); } void ShrinkToFit() { stack_.ShrinkToFit(); } Ch* Push(size_t count) { return stack_.template Push(count); } void Pop(size_t count) { stack_.template Pop(count); } const Ch* GetBuffer() const { return stack_.template Bottom(); } size_t GetSize() const { return stack_.GetSize(); } static const size_t kDefaultCapacity = 256; mutable internal::Stack stack_; }; typedef GenericMemoryBuffer<> MemoryBuffer; //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); } RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_MEMORYBUFFER_H_ osmium-tool-1.7.1/include/rapidjson/memorystream.h000066400000000000000000000051531315004223400223130ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_MEMORYSTREAM_H_ #define RAPIDJSON_MEMORYSTREAM_H_ #include "stream.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(missing-noreturn) #endif RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory input byte stream. /*! This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. Differences between MemoryStream and StringStream: 1. StringStream has encoding but MemoryStream is a byte stream. 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). \note implements Stream concept */ struct MemoryStream { typedef char Ch; // byte MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } size_t Tell() const { return static_cast(src_ - begin_); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. const Ch* Peek4() const { return Tell() + 4 <= size_ ? src_ : 0; } const Ch* src_; //!< Current read position. const Ch* begin_; //!< Original head of the string. const Ch* end_; //!< End of stream. size_t size_; //!< Size of the stream. }; RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_MEMORYBUFFER_H_ osmium-tool-1.7.1/include/rapidjson/msinttypes/000077500000000000000000000000001315004223400216315ustar00rootroot00000000000000osmium-tool-1.7.1/include/rapidjson/msinttypes/inttypes.h000066400000000000000000000202641315004223400236650ustar00rootroot00000000000000// ISO C9x compliant inttypes.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2013 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the name of the product nor the names of its contributors may // be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// // The above software in this distribution may have been modified by // THL A29 Limited ("Tencent Modifications"). // All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_INTTYPES_H_ // [ #define _MSC_INTTYPES_H_ #if _MSC_VER > 1000 #pragma once #endif #include "stdint.h" // miloyip: VC supports inttypes.h since VC2013 #if _MSC_VER >= 1800 #include #else // 7.8 Format conversion of integer types typedef struct { intmax_t quot; intmax_t rem; } imaxdiv_t; // 7.8.1 Macros for format specifiers #if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 // The fprintf macros for signed integers are: #define PRId8 "d" #define PRIi8 "i" #define PRIdLEAST8 "d" #define PRIiLEAST8 "i" #define PRIdFAST8 "d" #define PRIiFAST8 "i" #define PRId16 "hd" #define PRIi16 "hi" #define PRIdLEAST16 "hd" #define PRIiLEAST16 "hi" #define PRIdFAST16 "hd" #define PRIiFAST16 "hi" #define PRId32 "I32d" #define PRIi32 "I32i" #define PRIdLEAST32 "I32d" #define PRIiLEAST32 "I32i" #define PRIdFAST32 "I32d" #define PRIiFAST32 "I32i" #define PRId64 "I64d" #define PRIi64 "I64i" #define PRIdLEAST64 "I64d" #define PRIiLEAST64 "I64i" #define PRIdFAST64 "I64d" #define PRIiFAST64 "I64i" #define PRIdMAX "I64d" #define PRIiMAX "I64i" #define PRIdPTR "Id" #define PRIiPTR "Ii" // The fprintf macros for unsigned integers are: #define PRIo8 "o" #define PRIu8 "u" #define PRIx8 "x" #define PRIX8 "X" #define PRIoLEAST8 "o" #define PRIuLEAST8 "u" #define PRIxLEAST8 "x" #define PRIXLEAST8 "X" #define PRIoFAST8 "o" #define PRIuFAST8 "u" #define PRIxFAST8 "x" #define PRIXFAST8 "X" #define PRIo16 "ho" #define PRIu16 "hu" #define PRIx16 "hx" #define PRIX16 "hX" #define PRIoLEAST16 "ho" #define PRIuLEAST16 "hu" #define PRIxLEAST16 "hx" #define PRIXLEAST16 "hX" #define PRIoFAST16 "ho" #define PRIuFAST16 "hu" #define PRIxFAST16 "hx" #define PRIXFAST16 "hX" #define PRIo32 "I32o" #define PRIu32 "I32u" #define PRIx32 "I32x" #define PRIX32 "I32X" #define PRIoLEAST32 "I32o" #define PRIuLEAST32 "I32u" #define PRIxLEAST32 "I32x" #define PRIXLEAST32 "I32X" #define PRIoFAST32 "I32o" #define PRIuFAST32 "I32u" #define PRIxFAST32 "I32x" #define PRIXFAST32 "I32X" #define PRIo64 "I64o" #define PRIu64 "I64u" #define PRIx64 "I64x" #define PRIX64 "I64X" #define PRIoLEAST64 "I64o" #define PRIuLEAST64 "I64u" #define PRIxLEAST64 "I64x" #define PRIXLEAST64 "I64X" #define PRIoFAST64 "I64o" #define PRIuFAST64 "I64u" #define PRIxFAST64 "I64x" #define PRIXFAST64 "I64X" #define PRIoMAX "I64o" #define PRIuMAX "I64u" #define PRIxMAX "I64x" #define PRIXMAX "I64X" #define PRIoPTR "Io" #define PRIuPTR "Iu" #define PRIxPTR "Ix" #define PRIXPTR "IX" // The fscanf macros for signed integers are: #define SCNd8 "d" #define SCNi8 "i" #define SCNdLEAST8 "d" #define SCNiLEAST8 "i" #define SCNdFAST8 "d" #define SCNiFAST8 "i" #define SCNd16 "hd" #define SCNi16 "hi" #define SCNdLEAST16 "hd" #define SCNiLEAST16 "hi" #define SCNdFAST16 "hd" #define SCNiFAST16 "hi" #define SCNd32 "ld" #define SCNi32 "li" #define SCNdLEAST32 "ld" #define SCNiLEAST32 "li" #define SCNdFAST32 "ld" #define SCNiFAST32 "li" #define SCNd64 "I64d" #define SCNi64 "I64i" #define SCNdLEAST64 "I64d" #define SCNiLEAST64 "I64i" #define SCNdFAST64 "I64d" #define SCNiFAST64 "I64i" #define SCNdMAX "I64d" #define SCNiMAX "I64i" #ifdef _WIN64 // [ # define SCNdPTR "I64d" # define SCNiPTR "I64i" #else // _WIN64 ][ # define SCNdPTR "ld" # define SCNiPTR "li" #endif // _WIN64 ] // The fscanf macros for unsigned integers are: #define SCNo8 "o" #define SCNu8 "u" #define SCNx8 "x" #define SCNX8 "X" #define SCNoLEAST8 "o" #define SCNuLEAST8 "u" #define SCNxLEAST8 "x" #define SCNXLEAST8 "X" #define SCNoFAST8 "o" #define SCNuFAST8 "u" #define SCNxFAST8 "x" #define SCNXFAST8 "X" #define SCNo16 "ho" #define SCNu16 "hu" #define SCNx16 "hx" #define SCNX16 "hX" #define SCNoLEAST16 "ho" #define SCNuLEAST16 "hu" #define SCNxLEAST16 "hx" #define SCNXLEAST16 "hX" #define SCNoFAST16 "ho" #define SCNuFAST16 "hu" #define SCNxFAST16 "hx" #define SCNXFAST16 "hX" #define SCNo32 "lo" #define SCNu32 "lu" #define SCNx32 "lx" #define SCNX32 "lX" #define SCNoLEAST32 "lo" #define SCNuLEAST32 "lu" #define SCNxLEAST32 "lx" #define SCNXLEAST32 "lX" #define SCNoFAST32 "lo" #define SCNuFAST32 "lu" #define SCNxFAST32 "lx" #define SCNXFAST32 "lX" #define SCNo64 "I64o" #define SCNu64 "I64u" #define SCNx64 "I64x" #define SCNX64 "I64X" #define SCNoLEAST64 "I64o" #define SCNuLEAST64 "I64u" #define SCNxLEAST64 "I64x" #define SCNXLEAST64 "I64X" #define SCNoFAST64 "I64o" #define SCNuFAST64 "I64u" #define SCNxFAST64 "I64x" #define SCNXFAST64 "I64X" #define SCNoMAX "I64o" #define SCNuMAX "I64u" #define SCNxMAX "I64x" #define SCNXMAX "I64X" #ifdef _WIN64 // [ # define SCNoPTR "I64o" # define SCNuPTR "I64u" # define SCNxPTR "I64x" # define SCNXPTR "I64X" #else // _WIN64 ][ # define SCNoPTR "lo" # define SCNuPTR "lu" # define SCNxPTR "lx" # define SCNXPTR "lX" #endif // _WIN64 ] #endif // __STDC_FORMAT_MACROS ] // 7.8.2 Functions for greatest-width integer types // 7.8.2.1 The imaxabs function #define imaxabs _abs64 // 7.8.2.2 The imaxdiv function // This is modified version of div() function from Microsoft's div.c found // in %MSVC.NET%\crt\src\div.c #ifdef STATIC_IMAXDIV // [ static #else // STATIC_IMAXDIV ][ _inline #endif // STATIC_IMAXDIV ] imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) { imaxdiv_t result; result.quot = numer / denom; result.rem = numer % denom; if (numer < 0 && result.rem > 0) { // did division wrong; must fix up ++result.quot; result.rem -= denom; } return result; } // 7.8.2.3 The strtoimax and strtoumax functions #define strtoimax _strtoi64 #define strtoumax _strtoui64 // 7.8.2.4 The wcstoimax and wcstoumax functions #define wcstoimax _wcstoi64 #define wcstoumax _wcstoui64 #endif // _MSC_VER >= 1800 #endif // _MSC_INTTYPES_H_ ] osmium-tool-1.7.1/include/rapidjson/msinttypes/stdint.h000066400000000000000000000222521315004223400233120ustar00rootroot00000000000000// ISO C9x compliant stdint.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2013 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the name of the product nor the names of its contributors may // be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// // The above software in this distribution may have been modified by // THL A29 Limited ("Tencent Modifications"). // All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_STDINT_H_ // [ #define _MSC_STDINT_H_ #if _MSC_VER > 1000 #pragma once #endif // miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010. #if _MSC_VER >= 1600 // [ #include #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 #undef INT8_C #undef INT16_C #undef INT32_C #undef INT64_C #undef UINT8_C #undef UINT16_C #undef UINT32_C #undef UINT64_C // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 #define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 // 7.18.4.2 Macros for greatest-width integer constants // These #ifndef's are needed to prevent collisions with . // Check out Issue 9 for the details. #ifndef INTMAX_C // [ # define INTMAX_C INT64_C #endif // INTMAX_C ] #ifndef UINTMAX_C // [ # define UINTMAX_C UINT64_C #endif // UINTMAX_C ] #endif // __STDC_CONSTANT_MACROS ] #else // ] _MSC_VER >= 1700 [ #include // For Visual Studio 6 in C++ mode and for many Visual Studio versions when // compiling for ARM we have to wrap include with 'extern "C++" {}' // or compiler would give many errors like this: // error C2733: second C linkage of overloaded function 'wmemchr' not allowed #if defined(__cplusplus) && !defined(_M_ARM) extern "C" { #endif # include #if defined(__cplusplus) && !defined(_M_ARM) } #endif // Define _W64 macros to mark types changing their size, like intptr_t. #ifndef _W64 # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 # define _W64 __w64 # else # define _W64 # endif #endif // 7.18.1 Integer types // 7.18.1.1 Exact-width integer types // Visual Studio 6 and Embedded Visual C++ 4 doesn't // realize that, e.g. char has the same size as __int8 // so we give up on __intX for them. #if (_MSC_VER < 1300) typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #else typedef signed __int8 int8_t; typedef signed __int16 int16_t; typedef signed __int32 int32_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; #endif typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; // 7.18.1.2 Minimum-width integer types typedef int8_t int_least8_t; typedef int16_t int_least16_t; typedef int32_t int_least32_t; typedef int64_t int_least64_t; typedef uint8_t uint_least8_t; typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; typedef uint64_t uint_least64_t; // 7.18.1.3 Fastest minimum-width integer types typedef int8_t int_fast8_t; typedef int16_t int_fast16_t; typedef int32_t int_fast32_t; typedef int64_t int_fast64_t; typedef uint8_t uint_fast8_t; typedef uint16_t uint_fast16_t; typedef uint32_t uint_fast32_t; typedef uint64_t uint_fast64_t; // 7.18.1.4 Integer types capable of holding object pointers #ifdef _WIN64 // [ typedef signed __int64 intptr_t; typedef unsigned __int64 uintptr_t; #else // _WIN64 ][ typedef _W64 signed int intptr_t; typedef _W64 unsigned int uintptr_t; #endif // _WIN64 ] // 7.18.1.5 Greatest-width integer types typedef int64_t intmax_t; typedef uint64_t uintmax_t; // 7.18.2 Limits of specified-width integer types #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 // 7.18.2.1 Limits of exact-width integer types #define INT8_MIN ((int8_t)_I8_MIN) #define INT8_MAX _I8_MAX #define INT16_MIN ((int16_t)_I16_MIN) #define INT16_MAX _I16_MAX #define INT32_MIN ((int32_t)_I32_MIN) #define INT32_MAX _I32_MAX #define INT64_MIN ((int64_t)_I64_MIN) #define INT64_MAX _I64_MAX #define UINT8_MAX _UI8_MAX #define UINT16_MAX _UI16_MAX #define UINT32_MAX _UI32_MAX #define UINT64_MAX _UI64_MAX // 7.18.2.2 Limits of minimum-width integer types #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MAX INT8_MAX #define INT_LEAST16_MIN INT16_MIN #define INT_LEAST16_MAX INT16_MAX #define INT_LEAST32_MIN INT32_MIN #define INT_LEAST32_MAX INT32_MAX #define INT_LEAST64_MIN INT64_MIN #define INT_LEAST64_MAX INT64_MAX #define UINT_LEAST8_MAX UINT8_MAX #define UINT_LEAST16_MAX UINT16_MAX #define UINT_LEAST32_MAX UINT32_MAX #define UINT_LEAST64_MAX UINT64_MAX // 7.18.2.3 Limits of fastest minimum-width integer types #define INT_FAST8_MIN INT8_MIN #define INT_FAST8_MAX INT8_MAX #define INT_FAST16_MIN INT16_MIN #define INT_FAST16_MAX INT16_MAX #define INT_FAST32_MIN INT32_MIN #define INT_FAST32_MAX INT32_MAX #define INT_FAST64_MIN INT64_MIN #define INT_FAST64_MAX INT64_MAX #define UINT_FAST8_MAX UINT8_MAX #define UINT_FAST16_MAX UINT16_MAX #define UINT_FAST32_MAX UINT32_MAX #define UINT_FAST64_MAX UINT64_MAX // 7.18.2.4 Limits of integer types capable of holding object pointers #ifdef _WIN64 // [ # define INTPTR_MIN INT64_MIN # define INTPTR_MAX INT64_MAX # define UINTPTR_MAX UINT64_MAX #else // _WIN64 ][ # define INTPTR_MIN INT32_MIN # define INTPTR_MAX INT32_MAX # define UINTPTR_MAX UINT32_MAX #endif // _WIN64 ] // 7.18.2.5 Limits of greatest-width integer types #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX // 7.18.3 Limits of other integer types #ifdef _WIN64 // [ # define PTRDIFF_MIN _I64_MIN # define PTRDIFF_MAX _I64_MAX #else // _WIN64 ][ # define PTRDIFF_MIN _I32_MIN # define PTRDIFF_MAX _I32_MAX #endif // _WIN64 ] #define SIG_ATOMIC_MIN INT_MIN #define SIG_ATOMIC_MAX INT_MAX #ifndef SIZE_MAX // [ # ifdef _WIN64 // [ # define SIZE_MAX _UI64_MAX # else // _WIN64 ][ # define SIZE_MAX _UI32_MAX # endif // _WIN64 ] #endif // SIZE_MAX ] // WCHAR_MIN and WCHAR_MAX are also defined in #ifndef WCHAR_MIN // [ # define WCHAR_MIN 0 #endif // WCHAR_MIN ] #ifndef WCHAR_MAX // [ # define WCHAR_MAX _UI16_MAX #endif // WCHAR_MAX ] #define WINT_MIN 0 #define WINT_MAX _UI16_MAX #endif // __STDC_LIMIT_MACROS ] // 7.18.4 Limits of other integer types #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 #define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 // 7.18.4.2 Macros for greatest-width integer constants // These #ifndef's are needed to prevent collisions with . // Check out Issue 9 for the details. #ifndef INTMAX_C // [ # define INTMAX_C INT64_C #endif // INTMAX_C ] #ifndef UINTMAX_C // [ # define UINTMAX_C UINT64_C #endif // UINTMAX_C ] #endif // __STDC_CONSTANT_MACROS ] #endif // _MSC_VER >= 1600 ] #endif // _MSC_STDINT_H_ ] osmium-tool-1.7.1/include/rapidjson/ostreamwrapper.h000066400000000000000000000044331315004223400226420ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_OSTREAMWRAPPER_H_ #define RAPIDJSON_OSTREAMWRAPPER_H_ #include "stream.h" #include #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. /*! The classes can be wrapped including but not limited to: - \c std::ostringstream - \c std::stringstream - \c std::wpstringstream - \c std::wstringstream - \c std::ifstream - \c std::fstream - \c std::wofstream - \c std::wfstream \tparam StreamType Class derived from \c std::basic_ostream. */ template class BasicOStreamWrapper { public: typedef typename StreamType::char_type Ch; BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} void Put(Ch c) { stream_.put(c); } void Flush() { stream_.flush(); } // Not implemented char Peek() const { RAPIDJSON_ASSERT(false); return 0; } char Take() { RAPIDJSON_ASSERT(false); return 0; } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } private: BasicOStreamWrapper(const BasicOStreamWrapper&); BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); StreamType& stream_; }; typedef BasicOStreamWrapper OStreamWrapper; typedef BasicOStreamWrapper WOStreamWrapper; #ifdef __clang__ RAPIDJSON_DIAG_POP #endif RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_OSTREAMWRAPPER_H_ osmium-tool-1.7.1/include/rapidjson/pointer.h000066400000000000000000001621411315004223400212500ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_POINTER_H_ #define RAPIDJSON_POINTER_H_ #include "document.h" #include "internal/itoa.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(switch-enum) #endif #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif RAPIDJSON_NAMESPACE_BEGIN static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token //! Error code of parsing. /*! \ingroup RAPIDJSON_ERRORS \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode */ enum PointerParseErrorCode { kPointerParseErrorNone = 0, //!< The parse is successful kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' kPointerParseErrorInvalidEscape, //!< Invalid escape kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment }; /////////////////////////////////////////////////////////////////////////////// // GenericPointer //! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator. /*! This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" (https://tools.ietf.org/html/rfc6901). A JSON pointer is for identifying a specific value in a JSON document (GenericDocument). It can simplify coding of DOM tree manipulation, because it can access multiple-level depth of DOM tree with single API call. After it parses a string representation (e.g. "/foo/0" or URI fragment representation (e.g. "#/foo/0") into its internal representation (tokens), it can be used to resolve a specific value in multiple documents, or sub-tree of documents. Contrary to GenericValue, Pointer can be copy constructed and copy assigned. Apart from assignment, a Pointer cannot be modified after construction. Although Pointer is very convenient, please aware that constructing Pointer involves parsing and dynamic memory allocation. A special constructor with user- supplied tokens eliminates these. GenericPointer depends on GenericDocument and GenericValue. \tparam ValueType The value type of the DOM tree. E.g. GenericValue > \tparam Allocator The allocator type for allocating memory for internal representation. \note GenericPointer uses same encoding of ValueType. However, Allocator of GenericPointer is independent of Allocator of Value. */ template class GenericPointer { public: typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value typedef typename ValueType::Ch Ch; //!< Character type from Value //! A token is the basic units of internal representation. /*! A JSON pointer string representation "/foo/123" is parsed to two tokens: "foo" and 123. 123 will be represented in both numeric form and string form. They are resolved according to the actual value type (object or array). For token that are not numbers, or the numeric value is out of bound (greater than limits of SizeType), they are only treated as string form (i.e. the token's index will be equal to kPointerInvalidIndex). This struct is public so that user can create a Pointer without parsing and allocation, using a special constructor. */ struct Token { const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character. SizeType length; //!< Length of the name. SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. }; //!@name Constructors and destructor. //@{ //! Default constructor. GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} //! Constructor that parses a string or URI fragment representation. /*! \param source A null-terminated, string or URI fragment representation of JSON pointer. \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. */ explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { Parse(source, internal::StrLen(source)); } #if RAPIDJSON_HAS_STDSTRING //! Constructor that parses a string or URI fragment representation. /*! \param source A string or URI fragment representation of JSON pointer. \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ explicit GenericPointer(const std::basic_string& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { Parse(source.c_str(), source.size()); } #endif //! Constructor that parses a string or URI fragment representation, with length of the source string. /*! \param source A string or URI fragment representation of JSON pointer. \param length Length of source. \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. \note Slightly faster than the overload without length. */ GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { Parse(source, length); } //! Constructor with user-supplied tokens. /*! This constructor let user supplies const array of tokens. This prevents the parsing process and eliminates allocation. This is preferred for memory constrained environments. \param tokens An constant array of tokens representing the JSON pointer. \param tokenCount Number of tokens. \b Example \code #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } #define INDEX(i) { #i, sizeof(#i) - 1, i } static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); // Equivalent to static const Pointer p("/foo/123"); #undef NAME #undef INDEX \endcode */ GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} //! Copy constructor. GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { *this = rhs; } //! Destructor. ~GenericPointer() { if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. Allocator::Free(tokens_); RAPIDJSON_DELETE(ownAllocator_); } //! Assignment operator. GenericPointer& operator=(const GenericPointer& rhs) { if (this != &rhs) { // Do not delete ownAllcator if (nameBuffer_) Allocator::Free(tokens_); tokenCount_ = rhs.tokenCount_; parseErrorOffset_ = rhs.parseErrorOffset_; parseErrorCode_ = rhs.parseErrorCode_; if (rhs.nameBuffer_) CopyFromRaw(rhs); // Normally parsed tokens. else { tokens_ = rhs.tokens_; // User supplied const tokens. nameBuffer_ = 0; } } return *this; } //@} //!@name Append token //@{ //! Append a token and return a new Pointer /*! \param token Token to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const Token& token, Allocator* allocator = 0) const { GenericPointer r; r.allocator_ = allocator; Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); r.tokens_[tokenCount_].name = p; r.tokens_[tokenCount_].length = token.length; r.tokens_[tokenCount_].index = token.index; return r; } //! Append a name token with length, and return a new Pointer /*! \param name Name to be appended. \param length Length of name. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const { Token token = { name, length, kPointerInvalidIndex }; return Append(token, allocator); } //! Append a name token without length, and return a new Pointer /*! \param name Name (const Ch*) to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) Append(T* name, Allocator* allocator = 0) const { return Append(name, StrLen(name), allocator); } #if RAPIDJSON_HAS_STDSTRING //! Append a name token, and return a new Pointer /*! \param name Name to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const std::basic_string& name, Allocator* allocator = 0) const { return Append(name.c_str(), static_cast(name.size()), allocator); } #endif //! Append a index token, and return a new Pointer /*! \param index Index to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(SizeType index, Allocator* allocator = 0) const { char buffer[21]; char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer); SizeType length = static_cast(end - buffer); buffer[length] = '\0'; if (sizeof(Ch) == 1) { Token token = { reinterpret_cast(buffer), length, index }; return Append(token, allocator); } else { Ch name[21]; for (size_t i = 0; i <= length; i++) name[i] = buffer[i]; Token token = { name, length, index }; return Append(token, allocator); } } //! Append a token by value, and return a new Pointer /*! \param token token to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const { if (token.IsString()) return Append(token.GetString(), token.GetStringLength(), allocator); else { RAPIDJSON_ASSERT(token.IsUint64()); RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); return Append(static_cast(token.GetUint64()), allocator); } } //!@name Handling Parse Error //@{ //! Check whether this is a valid pointer. bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; } //! Get the parsing error offset in code unit. size_t GetParseErrorOffset() const { return parseErrorOffset_; } //! Get the parsing error code. PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; } //@} //! Get the allocator of this pointer. Allocator& GetAllocator() { return *allocator_; } //!@name Tokens //@{ //! Get the token array (const version only). const Token* GetTokens() const { return tokens_; } //! Get the number of tokens. size_t GetTokenCount() const { return tokenCount_; } //@} //!@name Equality/inequality operators //@{ //! Equality operator. /*! \note When any pointers are invalid, always returns false. */ bool operator==(const GenericPointer& rhs) const { if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_) return false; for (size_t i = 0; i < tokenCount_; i++) { if (tokens_[i].index != rhs.tokens_[i].index || tokens_[i].length != rhs.tokens_[i].length || (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) { return false; } } return true; } //! Inequality operator. /*! \note When any pointers are invalid, always returns true. */ bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } //@} //!@name Stringify //@{ //! Stringify the pointer into string representation. /*! \tparam OutputStream Type of output stream. \param os The output stream. */ template bool Stringify(OutputStream& os) const { return Stringify(os); } //! Stringify the pointer into URI fragment representation. /*! \tparam OutputStream Type of output stream. \param os The output stream. */ template bool StringifyUriFragment(OutputStream& os) const { return Stringify(os); } //@} //!@name Create value //@{ //! Create a value in a subtree. /*! If the value is not exist, it creates all parent values and a JSON Null value. So it always succeed and return the newly created or existing value. Remind that it may change types of parents according to tokens, so it potentially removes previously stored values. For example, if a document was an array, and "/foo" is used to create a value, then the document will be changed to an object, and all existing array elements are lost. \param root Root value of a DOM subtree to be resolved. It can be any value other than document root. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \param alreadyExist If non-null, it stores whether the resolved value is already exist. \return The resolved newly created (a JSON Null value), or already exists value. */ ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const { RAPIDJSON_ASSERT(IsValid()); ValueType* v = &root; bool exist = true; for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { if (v->IsArray() && t->name[0] == '-' && t->length == 1) { v->PushBack(ValueType().Move(), allocator); v = &((*v)[v->Size() - 1]); exist = false; } else { if (t->index == kPointerInvalidIndex) { // must be object name if (!v->IsObject()) v->SetObject(); // Change to Object } else { // object name or array index if (!v->IsArray() && !v->IsObject()) v->SetArray(); // Change to Array } if (v->IsArray()) { if (t->index >= v->Size()) { v->Reserve(t->index + 1, allocator); while (t->index >= v->Size()) v->PushBack(ValueType().Move(), allocator); exist = false; } v = &((*v)[t->index]); } else { typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); if (m == v->MemberEnd()) { v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end exist = false; } else v = &m->value; } } } if (alreadyExist) *alreadyExist = exist; return *v; } //! Creates a value in a document. /*! \param document A document to be resolved. \param alreadyExist If non-null, it stores whether the resolved value is already exist. \return The resolved newly created, or already exists value. */ template ValueType& Create(GenericDocument& document, bool* alreadyExist = 0) const { return Create(document, document.GetAllocator(), alreadyExist); } //@} //!@name Query value //@{ //! Query a value in a subtree. /*! \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. \return Pointer to the value if it can be resolved. Otherwise null. \note There are only 3 situations when a value cannot be resolved: 1. A value in the path is not an array nor object. 2. An object value does not contain the token. 3. A token is out of range of an array value. Use unresolvedTokenIndex to retrieve the token index. */ ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { RAPIDJSON_ASSERT(IsValid()); ValueType* v = &root; for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { switch (v->GetType()) { case kObjectType: { typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); if (m == v->MemberEnd()) break; v = &m->value; } continue; case kArrayType: if (t->index == kPointerInvalidIndex || t->index >= v->Size()) break; v = &((*v)[t->index]); continue; default: break; } // Error: unresolved token if (unresolvedTokenIndex) *unresolvedTokenIndex = static_cast(t - tokens_); return 0; } return v; } //! Query a const value in a const subtree. /*! \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \return Pointer to the value if it can be resolved. Otherwise null. */ const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { return Get(const_cast(root), unresolvedTokenIndex); } //@} //!@name Query a value with default //@{ //! Query a value in a subtree with default value. /*! Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value. So that this function always succeed. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param defaultValue Default value to be cloned if the value was not exists. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \see Create() */ ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; Value& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); } //! Query a value in a subtree with default null-terminated string. ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; Value& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } #if RAPIDJSON_HAS_STDSTRING //! Query a value in a subtree with default std::basic_string. ValueType& GetWithDefault(ValueType& root, const std::basic_string& defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; Value& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } #endif //! Query a value in a subtree with default primitive value. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const { return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); } //! Query a value in a document with default value. template ValueType& GetWithDefault(GenericDocument& document, const ValueType& defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } //! Query a value in a document with default null-terminated string. template ValueType& GetWithDefault(GenericDocument& document, const Ch* defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } #if RAPIDJSON_HAS_STDSTRING //! Query a value in a document with default std::basic_string. template ValueType& GetWithDefault(GenericDocument& document, const std::basic_string& defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } #endif //! Query a value in a document with default primitive value. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) GetWithDefault(GenericDocument& document, T defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } //@} //!@name Set a value //@{ //! Set a value in a subtree, with move semantics. /*! It creates all parents if they are not exist or types are different to the tokens. So this function always succeeds but potentially remove existing values. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param value Value to be set. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \see Create() */ ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = value; } //! Set a value in a subtree, with copy semantics. ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator).CopyFrom(value, allocator); } //! Set a null-terminated string in a subtree. ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = ValueType(value, allocator).Move(); } #if RAPIDJSON_HAS_STDSTRING //! Set a std::basic_string in a subtree. ValueType& Set(ValueType& root, const std::basic_string& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = ValueType(value, allocator).Move(); } #endif //! Set a primitive value in a subtree. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = ValueType(value).Move(); } //! Set a value in a document, with move semantics. template ValueType& Set(GenericDocument& document, ValueType& value) const { return Create(document) = value; } //! Set a value in a document, with copy semantics. template ValueType& Set(GenericDocument& document, const ValueType& value) const { return Create(document).CopyFrom(value, document.GetAllocator()); } //! Set a null-terminated string in a document. template ValueType& Set(GenericDocument& document, const Ch* value) const { return Create(document) = ValueType(value, document.GetAllocator()).Move(); } #if RAPIDJSON_HAS_STDSTRING //! Sets a std::basic_string in a document. template ValueType& Set(GenericDocument& document, const std::basic_string& value) const { return Create(document) = ValueType(value, document.GetAllocator()).Move(); } #endif //! Set a primitive value in a document. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) Set(GenericDocument& document, T value) const { return Create(document) = value; } //@} //!@name Swap a value //@{ //! Swap a value with a value in a subtree. /*! It creates all parents if they are not exist or types are different to the tokens. So this function always succeeds but potentially remove existing values. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param value Value to be swapped. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \see Create() */ ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator).Swap(value); } //! Swap a value with a value in a document. template ValueType& Swap(GenericDocument& document, ValueType& value) const { return Create(document).Swap(value); } //@} //! Erase a value in a subtree. /*! \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \return Whether the resolved value is found and erased. \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. */ bool Erase(ValueType& root) const { RAPIDJSON_ASSERT(IsValid()); if (tokenCount_ == 0) // Cannot erase the root return false; ValueType* v = &root; const Token* last = tokens_ + (tokenCount_ - 1); for (const Token *t = tokens_; t != last; ++t) { switch (v->GetType()) { case kObjectType: { typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); if (m == v->MemberEnd()) return false; v = &m->value; } break; case kArrayType: if (t->index == kPointerInvalidIndex || t->index >= v->Size()) return false; v = &((*v)[t->index]); break; default: return false; } } switch (v->GetType()) { case kObjectType: return v->EraseMember(GenericStringRef(last->name, last->length)); case kArrayType: if (last->index == kPointerInvalidIndex || last->index >= v->Size()) return false; v->Erase(v->Begin() + last->index); return true; default: return false; } } private: //! Clone the content from rhs to this. /*! \param rhs Source pointer. \param extraToken Extra tokens to be allocated. \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated. \return Start of non-occupied name buffer, for storing extra names. */ Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { if (!allocator_) // allocator is independently owned. ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) nameBufferSize += t->length; tokenCount_ = rhs.tokenCount_ + extraToken; tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); if (rhs.tokenCount_ > 0) { std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); } if (nameBufferSize > 0) { std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); } // Adjust pointers to name buffer std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) t->name += diff; return nameBuffer_ + nameBufferSize; } //! Check whether a character should be percent-encoded. /*! According to RFC 3986 2.3 Unreserved Characters. \param c The character (code unit) to be tested. */ bool NeedPercentEncode(Ch c) const { return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); } //! Parse a JSON String or its URI fragment representation into tokens. #ifndef __clang__ // -Wdocumentation /*! \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. \param length Length of the source string. \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. */ #endif void Parse(const Ch* source, size_t length) { RAPIDJSON_ASSERT(source != NULL); RAPIDJSON_ASSERT(nameBuffer_ == 0); RAPIDJSON_ASSERT(tokens_ == 0); // Create own allocator if user did not supply. if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); // Count number of '/' as tokenCount tokenCount_ = 0; for (const Ch* s = source; s != source + length; s++) if (*s == '/') tokenCount_++; Token* token = tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); Ch* name = nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); size_t i = 0; // Detect if it is a URI fragment bool uriFragment = false; if (source[i] == '#') { uriFragment = true; i++; } if (i != length && source[i] != '/') { parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus; goto error; } while (i < length) { RAPIDJSON_ASSERT(source[i] == '/'); i++; // consumes '/' token->name = name; bool isNumber = true; while (i < length && source[i] != '/') { Ch c = source[i]; if (uriFragment) { // Decoding percent-encoding for URI fragment if (c == '%') { PercentDecodeStream is(&source[i], source + length); GenericInsituStringStream os(name); Ch* begin = os.PutBegin(); if (!Transcoder, EncodingType>().Validate(is, os) || !is.IsValid()) { parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding; goto error; } size_t len = os.PutEnd(begin); i += is.Tell() - 1; if (len == 1) c = *name; else { name += len; isNumber = false; i++; continue; } } else if (NeedPercentEncode(c)) { parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode; goto error; } } i++; // Escaping "~0" -> '~', "~1" -> '/' if (c == '~') { if (i < length) { c = source[i]; if (c == '0') c = '~'; else if (c == '1') c = '/'; else { parseErrorCode_ = kPointerParseErrorInvalidEscape; goto error; } i++; } else { parseErrorCode_ = kPointerParseErrorInvalidEscape; goto error; } } // First check for index: all of characters are digit if (c < '0' || c > '9') isNumber = false; *name++ = c; } token->length = static_cast(name - token->name); if (token->length == 0) isNumber = false; *name++ = '\0'; // Null terminator // Second check for index: more than one digit cannot have leading zero if (isNumber && token->length > 1 && token->name[0] == '0') isNumber = false; // String to SizeType conversion SizeType n = 0; if (isNumber) { for (size_t j = 0; j < token->length; j++) { SizeType m = n * 10 + static_cast(token->name[j] - '0'); if (m < n) { // overflow detection isNumber = false; break; } n = m; } } token->index = isNumber ? n : kPointerInvalidIndex; token++; } RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer parseErrorCode_ = kPointerParseErrorNone; return; error: Allocator::Free(tokens_); nameBuffer_ = 0; tokens_ = 0; tokenCount_ = 0; parseErrorOffset_ = i; return; } //! Stringify to string or URI fragment representation. /*! \tparam uriFragment True for stringifying to URI fragment representation. False for string representation. \tparam OutputStream type of output stream. \param os The output stream. */ template bool Stringify(OutputStream& os) const { RAPIDJSON_ASSERT(IsValid()); if (uriFragment) os.Put('#'); for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { os.Put('/'); for (size_t j = 0; j < t->length; j++) { Ch c = t->name[j]; if (c == '~') { os.Put('~'); os.Put('0'); } else if (c == '/') { os.Put('~'); os.Put('1'); } else if (uriFragment && NeedPercentEncode(c)) { // Transcode to UTF8 sequence GenericStringStream source(&t->name[j]); PercentEncodeStream target(os); if (!Transcoder >().Validate(source, target)) return false; j += source.Tell() - 1; } else os.Put(c); } } return true; } //! A helper stream for decoding a percent-encoded sequence into code unit. /*! This stream decodes %XY triplet into code unit (0-255). If it encounters invalid characters, it sets output code unit as 0 and mark invalid, and to be checked by IsValid(). */ class PercentDecodeStream { public: typedef typename ValueType::Ch Ch; //! Constructor /*! \param source Start of the stream \param end Past-the-end of the stream. */ PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {} Ch Take() { if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet valid_ = false; return 0; } src_++; Ch c = 0; for (int j = 0; j < 2; j++) { c = static_cast(c << 4); Ch h = *src_; if (h >= '0' && h <= '9') c = static_cast(c + h - '0'); else if (h >= 'A' && h <= 'F') c = static_cast(c + h - 'A' + 10); else if (h >= 'a' && h <= 'f') c = static_cast(c + h - 'a' + 10); else { valid_ = false; return 0; } src_++; } return c; } size_t Tell() const { return static_cast(src_ - head_); } bool IsValid() const { return valid_; } private: const Ch* src_; //!< Current read position. const Ch* head_; //!< Original head of the string. const Ch* end_; //!< Past-the-end position. bool valid_; //!< Whether the parsing is valid. }; //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. template class PercentEncodeStream { public: PercentEncodeStream(OutputStream& os) : os_(os) {} void Put(char c) { // UTF-8 must be byte unsigned char u = static_cast(c); static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; os_.Put('%'); os_.Put(hexDigits[u >> 4]); os_.Put(hexDigits[u & 15]); } private: OutputStream& os_; }; Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. Allocator* ownAllocator_; //!< Allocator owned by this Pointer. Ch* nameBuffer_; //!< A buffer containing all names in tokens. Token* tokens_; //!< A list of tokens. size_t tokenCount_; //!< Number of tokens in tokens_. size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. PointerParseErrorCode parseErrorCode_; //!< Parsing error code. }; //! GenericPointer for Value (UTF-8, default allocator). typedef GenericPointer Pointer; //!@name Helper functions for GenericPointer //@{ ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer& pointer, typename T::AllocatorType& a) { return pointer.Create(root, a); } template typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Create(root, a); } // No allocator parameter template typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer& pointer) { return pointer.Create(document); } template typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) { return GenericPointer(source, N - 1).Create(document); } ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType* GetValueByPointer(T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { return pointer.Get(root, unresolvedTokenIndex); } template const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { return pointer.Get(root, unresolvedTokenIndex); } template typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) { return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); } template const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) { return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); } ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } template typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } #if RAPIDJSON_HAS_STDSTRING template typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const std::basic_string& defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, T2 defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } template typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); } template typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); } #if RAPIDJSON_HAS_STDSTRING template typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string& defaultValue, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); } // No allocator parameter template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& defaultValue) { return pointer.GetWithDefault(document, defaultValue); } template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* defaultValue) { return pointer.GetWithDefault(document, defaultValue); } #if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const std::basic_string& defaultValue) { return pointer.GetWithDefault(document, defaultValue); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, T2 defaultValue) { return pointer.GetWithDefault(document, defaultValue); } template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) { return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); } template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) { return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); } #if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string& defaultValue) { return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) { return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); } ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::Ch* value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } #if RAPIDJSON_HAS_STDSTRING template typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const std::basic_string& value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) SetValueByPointer(T& root, const GenericPointer& pointer, T2 value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } #if RAPIDJSON_HAS_STDSTRING template typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string& value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } // No allocator parameter template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { return pointer.Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& value) { return pointer.Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* value) { return pointer.Set(document, value); } #if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const std::basic_string& value) { return pointer.Set(document, value); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) SetValueByPointer(DocumentType& document, const GenericPointer& pointer, T2 value) { return pointer.Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { return GenericPointer(source, N - 1).Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) { return GenericPointer(source, N - 1).Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) { return GenericPointer(source, N - 1).Set(document, value); } #if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string& value) { return GenericPointer(source, N - 1).Set(document, value); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) { return GenericPointer(source, N - 1).Set(document, value); } ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { return pointer.Swap(root, value, a); } template typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Swap(root, value, a); } template typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { return pointer.Swap(document, value); } template typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { return GenericPointer(source, N - 1).Swap(document, value); } ////////////////////////////////////////////////////////////////////////////// template bool EraseValueByPointer(T& root, const GenericPointer& pointer) { return pointer.Erase(root); } template bool EraseValueByPointer(T& root, const CharType(&source)[N]) { return GenericPointer(source, N - 1).Erase(root); } //@} RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #ifdef _MSC_VER RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_POINTER_H_ osmium-tool-1.7.1/include/rapidjson/prettywriter.h000066400000000000000000000226011315004223400223500ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_PRETTYWRITER_H_ #define RAPIDJSON_PRETTYWRITER_H_ #include "writer.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif RAPIDJSON_NAMESPACE_BEGIN //! Combination of PrettyWriter format flags. /*! \see PrettyWriter::SetFormatOptions */ enum PrettyFormatOptions { kFormatDefault = 0, //!< Default pretty formatting. kFormatSingleLineArray = 1 //!< Format arrays on a single line. }; //! Writer with indentation and spacing. /*! \tparam OutputStream Type of ouptut os. \tparam SourceEncoding Encoding of source string. \tparam TargetEncoding Encoding of output stream. \tparam StackAllocator Type of allocator for allocating memory of stack. */ template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> class PrettyWriter : public Writer { public: typedef Writer Base; typedef typename Base::Ch Ch; //! Constructor /*! \param os Output stream. \param allocator User supplied allocator. If it is null, it will create a private one. \param levelDepth Initial capacity of stack. */ explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} //! Set custom indentation. /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). \param indentCharCount Number of indent characters for each indentation level. \note The default indentation is 4 spaces. */ PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); indentChar_ = indentChar; indentCharCount_ = indentCharCount; return *this; } //! Set pretty writer formatting options. /*! \param options Formatting options. */ PrettyWriter& SetFormatOptions(PrettyFormatOptions options) { formatOptions_ = options; return *this; } /*! @name Implementation of Handler \see Handler */ //@{ bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } bool RawNumber(const Ch* str, SizeType length, bool copy = false) { (void)copy; PrettyPrefix(kNumberType); return Base::WriteString(str, length); } bool String(const Ch* str, SizeType length, bool copy = false) { (void)copy; PrettyPrefix(kStringType); return Base::WriteString(str, length); } #if RAPIDJSON_HAS_STDSTRING bool String(const std::basic_string& str) { return String(str.data(), SizeType(str.size())); } #endif bool StartObject() { PrettyPrefix(kObjectType); new (Base::level_stack_.template Push()) typename Base::Level(false); return Base::WriteStartObject(); } bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } #if RAPIDJSON_HAS_STDSTRING bool Key(const std::basic_string& str) { return Key(str.data(), SizeType(str.size())); } #endif bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty) { Base::os_->Put('\n'); WriteIndent(); } bool ret = Base::WriteEndObject(); (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text Base::os_->Flush(); return true; } bool StartArray() { PrettyPrefix(kArrayType); new (Base::level_stack_.template Push()) typename Base::Level(true); return Base::WriteStartArray(); } bool EndArray(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty && !(formatOptions_ & kFormatSingleLineArray)) { Base::os_->Put('\n'); WriteIndent(); } bool ret = Base::WriteEndArray(); (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text Base::os_->Flush(); return true; } //@} /*! @name Convenience extensions */ //@{ //! Simpler but slower overload. bool String(const Ch* str) { return String(str, internal::StrLen(str)); } bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } //@} //! Write a raw JSON value. /*! For user to write a stringified JSON as a value. \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. \param length Length of the json. \param type Type of the root of json. \note When using PrettyWriter::RawValue(), the result json may not be indented correctly. */ bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); } protected: void PrettyPrefix(Type type) { (void)type; if (Base::level_stack_.GetSize() != 0) { // this value is not at root typename Base::Level* level = Base::level_stack_.template Top(); if (level->inArray) { if (level->valueCount > 0) { Base::os_->Put(','); // add comma if it is not the first element in array if (formatOptions_ & kFormatSingleLineArray) Base::os_->Put(' '); } if (!(formatOptions_ & kFormatSingleLineArray)) { Base::os_->Put('\n'); WriteIndent(); } } else { // in object if (level->valueCount > 0) { if (level->valueCount % 2 == 0) { Base::os_->Put(','); Base::os_->Put('\n'); } else { Base::os_->Put(':'); Base::os_->Put(' '); } } else Base::os_->Put('\n'); if (level->valueCount % 2 == 0) WriteIndent(); } if (!level->inArray && level->valueCount % 2 == 0) RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name level->valueCount++; } else { RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. Base::hasRoot_ = true; } } void WriteIndent() { size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; PutN(*Base::os_, static_cast(indentChar_), count); } Ch indentChar_; unsigned indentCharCount_; PrettyFormatOptions formatOptions_; private: // Prohibit copy constructor & assignment operator. PrettyWriter(const PrettyWriter&); PrettyWriter& operator=(const PrettyWriter&); }; RAPIDJSON_NAMESPACE_END #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_RAPIDJSON_H_ osmium-tool-1.7.1/include/rapidjson/rapidjson.h000066400000000000000000000517251315004223400215660ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_RAPIDJSON_H_ #define RAPIDJSON_RAPIDJSON_H_ /*!\file rapidjson.h \brief common definitions and configuration \see RAPIDJSON_CONFIG */ /*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration \brief Configuration macros for library features Some RapidJSON features are configurable to adapt the library to a wide variety of platforms, environments and usage scenarios. Most of the features can be configured in terms of overriden or predefined preprocessor macros at compile-time. Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. \note These macros should be given on the compiler command-line (where applicable) to avoid inconsistent values when compiling different translation units of a single application. */ #include // malloc(), realloc(), free(), size_t #include // memset(), memcpy(), memmove(), memcmp() /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_VERSION_STRING // // ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. // //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN // token stringification #define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) #define RAPIDJSON_DO_STRINGIFY(x) #x //!@endcond /*! \def RAPIDJSON_MAJOR_VERSION \ingroup RAPIDJSON_CONFIG \brief Major version of RapidJSON in integer. */ /*! \def RAPIDJSON_MINOR_VERSION \ingroup RAPIDJSON_CONFIG \brief Minor version of RapidJSON in integer. */ /*! \def RAPIDJSON_PATCH_VERSION \ingroup RAPIDJSON_CONFIG \brief Patch version of RapidJSON in integer. */ /*! \def RAPIDJSON_VERSION_STRING \ingroup RAPIDJSON_CONFIG \brief Version of RapidJSON in ".." string format. */ #define RAPIDJSON_MAJOR_VERSION 1 #define RAPIDJSON_MINOR_VERSION 1 #define RAPIDJSON_PATCH_VERSION 0 #define RAPIDJSON_VERSION_STRING \ RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NAMESPACE_(BEGIN|END) /*! \def RAPIDJSON_NAMESPACE \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace In order to avoid symbol clashes and/or "One Definition Rule" errors between multiple inclusions of (different versions of) RapidJSON in a single binary, users can customize the name of the main RapidJSON namespace. In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref RAPIDJSON_NAMESPACE_END need to be defined as well: \code // in some .cpp file #define RAPIDJSON_NAMESPACE my::rapidjson #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { #define RAPIDJSON_NAMESPACE_END } } #include "rapidjson/..." \endcode \see rapidjson */ /*! \def RAPIDJSON_NAMESPACE_BEGIN \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace (opening expression) \see RAPIDJSON_NAMESPACE */ /*! \def RAPIDJSON_NAMESPACE_END \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace (closing expression) \see RAPIDJSON_NAMESPACE */ #ifndef RAPIDJSON_NAMESPACE #define RAPIDJSON_NAMESPACE rapidjson #endif #ifndef RAPIDJSON_NAMESPACE_BEGIN #define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { #endif #ifndef RAPIDJSON_NAMESPACE_END #define RAPIDJSON_NAMESPACE_END } #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_HAS_STDSTRING #ifndef RAPIDJSON_HAS_STDSTRING #ifdef RAPIDJSON_DOXYGEN_RUNNING #define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation #else #define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default #endif /*! \def RAPIDJSON_HAS_STDSTRING \ingroup RAPIDJSON_CONFIG \brief Enable RapidJSON support for \c std::string By defining this preprocessor symbol to \c 1, several convenience functions for using \ref rapidjson::GenericValue with \c std::string are enabled, especially for construction and comparison. \hideinitializer */ #endif // !defined(RAPIDJSON_HAS_STDSTRING) #if RAPIDJSON_HAS_STDSTRING #include #endif // RAPIDJSON_HAS_STDSTRING /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_INT64DEFINE /*! \def RAPIDJSON_NO_INT64DEFINE \ingroup RAPIDJSON_CONFIG \brief Use external 64-bit integer types. RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types to be available at global scope. If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to prevent RapidJSON from defining its own types. */ #ifndef RAPIDJSON_NO_INT64DEFINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 #include "msinttypes/stdint.h" #include "msinttypes/inttypes.h" #else // Other compilers should have this. #include #include #endif //!@endcond #ifdef RAPIDJSON_DOXYGEN_RUNNING #define RAPIDJSON_NO_INT64DEFINE #endif #endif // RAPIDJSON_NO_INT64TYPEDEF /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_FORCEINLINE #ifndef RAPIDJSON_FORCEINLINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #if defined(_MSC_VER) && defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __forceinline #elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) #else #define RAPIDJSON_FORCEINLINE #endif //!@endcond #endif // RAPIDJSON_FORCEINLINE /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ENDIAN #define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine #define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine //! Endianness of the machine. /*! \def RAPIDJSON_ENDIAN \ingroup RAPIDJSON_CONFIG GCC 4.6 provided macro for detecting endianness of the target machine. But other compilers may not have this. User can define RAPIDJSON_ENDIAN to either \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. Default detection implemented with reference to \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp */ #ifndef RAPIDJSON_ENDIAN // Detect with GCC 4.6's macro # ifdef __BYTE_ORDER__ # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else # error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. # endif // __BYTE_ORDER__ // Detect with GLIBC's endian.h # elif defined(__GLIBC__) # include # if (__BYTE_ORDER == __LITTLE_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif (__BYTE_ORDER == __BIG_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else # error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. # endif // __GLIBC__ // Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro # elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN // Detect with architecture macros # elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(_MSC_VER) && defined(_M_ARM) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(RAPIDJSON_DOXYGEN_RUNNING) # define RAPIDJSON_ENDIAN # else # error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. # endif #endif // RAPIDJSON_ENDIAN /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_64BIT //! Whether using 64-bit architecture #ifndef RAPIDJSON_64BIT #if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__) #define RAPIDJSON_64BIT 1 #else #define RAPIDJSON_64BIT 0 #endif #endif // RAPIDJSON_64BIT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ALIGN //! Data alignment of the machine. /*! \ingroup RAPIDJSON_CONFIG \param x pointer to align Some machines require strict data alignment. Currently the default uses 4 bytes alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms. User can customize by defining the RAPIDJSON_ALIGN function macro. */ #ifndef RAPIDJSON_ALIGN #if RAPIDJSON_64BIT == 1 #define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) #else #define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u) #endif #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_UINT64_C2 //! Construct a 64-bit literal by a pair of 32-bit integer. /*! 64-bit literal with or without ULL suffix is prone to compiler warnings. UINT64_C() is C macro which cause compilation problems. Use this macro to define 64-bit constants by a pair of 32-bit integer. */ #ifndef RAPIDJSON_UINT64_C2 #define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_48BITPOINTER_OPTIMIZATION //! Use only lower 48-bit address for some pointers. /*! \ingroup RAPIDJSON_CONFIG This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address. The higher 16-bit can be used for storing other data. \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture. */ #ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION #if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) #define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 #else #define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 #endif #endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION #if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1 #if RAPIDJSON_64BIT != 1 #error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1 #endif #define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast((reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast(reinterpret_cast(x)))) #define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast(reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) #else #define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) #define RAPIDJSON_GETPOINTER(type, p) (p) #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD /*! \def RAPIDJSON_SIMD \ingroup RAPIDJSON_CONFIG \brief Enable SSE2/SSE4.2 optimization. RapidJSON supports optimized implementations for some parsing operations based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible processors. To enable these optimizations, two different symbols can be defined; \code // Enable SSE2 optimization. #define RAPIDJSON_SSE2 // Enable SSE4.2 optimization. #define RAPIDJSON_SSE42 \endcode \c RAPIDJSON_SSE42 takes precedence, if both are defined. If any of these symbols is defined, RapidJSON defines the macro \c RAPIDJSON_SIMD to indicate the availability of the optimized code. */ #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ || defined(RAPIDJSON_DOXYGEN_RUNNING) #define RAPIDJSON_SIMD #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_SIZETYPEDEFINE #ifndef RAPIDJSON_NO_SIZETYPEDEFINE /*! \def RAPIDJSON_NO_SIZETYPEDEFINE \ingroup RAPIDJSON_CONFIG \brief User-provided \c SizeType definition. In order to avoid using 32-bit size types for indexing strings and arrays, define this preprocessor symbol and provide the type rapidjson::SizeType before including RapidJSON: \code #define RAPIDJSON_NO_SIZETYPEDEFINE namespace rapidjson { typedef ::std::size_t SizeType; } #include "rapidjson/..." \endcode \see rapidjson::SizeType */ #ifdef RAPIDJSON_DOXYGEN_RUNNING #define RAPIDJSON_NO_SIZETYPEDEFINE #endif RAPIDJSON_NAMESPACE_BEGIN //! Size type (for string lengths, array sizes, etc.) /*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, instead of using \c size_t. Users may override the SizeType by defining \ref RAPIDJSON_NO_SIZETYPEDEFINE. */ typedef unsigned SizeType; RAPIDJSON_NAMESPACE_END #endif // always import std::size_t to rapidjson namespace RAPIDJSON_NAMESPACE_BEGIN using std::size_t; RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ASSERT //! Assertion. /*! \ingroup RAPIDJSON_CONFIG By default, rapidjson uses C \c assert() for internal assertions. User can override it by defining RAPIDJSON_ASSERT(x) macro. \note Parsing errors are handled and can be customized by the \ref RAPIDJSON_ERRORS APIs. */ #ifndef RAPIDJSON_ASSERT #include #define RAPIDJSON_ASSERT(x) assert(x) #endif // RAPIDJSON_ASSERT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_STATIC_ASSERT // Adopt from boost #ifndef RAPIDJSON_STATIC_ASSERT #ifndef __clang__ //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #endif RAPIDJSON_NAMESPACE_BEGIN template struct STATIC_ASSERTION_FAILURE; template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; template struct StaticAssertTest {}; RAPIDJSON_NAMESPACE_END #define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) #define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) #define RAPIDJSON_DO_JOIN2(X, Y) X##Y #if defined(__GNUC__) #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) #else #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #endif #ifndef __clang__ //!@endcond #endif /*! \def RAPIDJSON_STATIC_ASSERT \brief (Internal) macro to check for conditions at compile-time \param x compile-time condition \hideinitializer */ #define RAPIDJSON_STATIC_ASSERT(x) \ typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY //! Compiler branching hint for expression with high probability to be true. /*! \ingroup RAPIDJSON_CONFIG \param x Boolean expression likely to be true. */ #ifndef RAPIDJSON_LIKELY #if defined(__GNUC__) || defined(__clang__) #define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) #else #define RAPIDJSON_LIKELY(x) (x) #endif #endif //! Compiler branching hint for expression with low probability to be true. /*! \ingroup RAPIDJSON_CONFIG \param x Boolean expression unlikely to be true. */ #ifndef RAPIDJSON_UNLIKELY #if defined(__GNUC__) || defined(__clang__) #define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) #else #define RAPIDJSON_UNLIKELY(x) (x) #endif #endif /////////////////////////////////////////////////////////////////////////////// // Helpers //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define RAPIDJSON_MULTILINEMACRO_BEGIN do { #define RAPIDJSON_MULTILINEMACRO_END \ } while((void)0, 0) // adopted from Boost #define RAPIDJSON_VERSION_CODE(x,y,z) \ (((x)*100000) + ((y)*100) + (z)) /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF #if defined(__GNUC__) #define RAPIDJSON_GNUC \ RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) #endif #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) #define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) #define RAPIDJSON_DIAG_OFF(x) \ RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) // push/pop support in Clang and GCC>=4.6 #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) #define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) #define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) #else // GCC >= 4.2, < 4.6 #define RAPIDJSON_DIAG_PUSH /* ignored */ #define RAPIDJSON_DIAG_POP /* ignored */ #endif #elif defined(_MSC_VER) // pragma (MSVC specific) #define RAPIDJSON_PRAGMA(x) __pragma(x) #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) #define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) #define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) #define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) #else #define RAPIDJSON_DIAG_OFF(x) /* ignored */ #define RAPIDJSON_DIAG_PUSH /* ignored */ #define RAPIDJSON_DIAG_POP /* ignored */ #endif // RAPIDJSON_DIAG_* /////////////////////////////////////////////////////////////////////////////// // C++11 features #ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS #if defined(__clang__) #if __has_feature(cxx_rvalue_references) && \ (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #else #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 #endif #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ (defined(_MSC_VER) && _MSC_VER >= 1600) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #else #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 #endif #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS #ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT #if defined(__clang__) #define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) // (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported #define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 #else #define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 #endif #endif #if RAPIDJSON_HAS_CXX11_NOEXCEPT #define RAPIDJSON_NOEXCEPT noexcept #else #define RAPIDJSON_NOEXCEPT /* noexcept */ #endif // RAPIDJSON_HAS_CXX11_NOEXCEPT // no automatic detection, yet #ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS #define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 #endif #ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR #if defined(__clang__) #define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ (defined(_MSC_VER) && _MSC_VER >= 1700) #define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 #else #define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 #endif #endif // RAPIDJSON_HAS_CXX11_RANGE_FOR //!@endcond /////////////////////////////////////////////////////////////////////////////// // new/delete #ifndef RAPIDJSON_NEW ///! customization point for global \c new #define RAPIDJSON_NEW(x) new x #endif #ifndef RAPIDJSON_DELETE ///! customization point for global \c delete #define RAPIDJSON_DELETE(x) delete x #endif /////////////////////////////////////////////////////////////////////////////// // Type /*! \namespace rapidjson \brief main RapidJSON namespace \see RAPIDJSON_NAMESPACE */ RAPIDJSON_NAMESPACE_BEGIN //! Type of JSON value enum Type { kNullType = 0, //!< null kFalseType = 1, //!< false kTrueType = 2, //!< true kObjectType = 3, //!< object kArrayType = 4, //!< array kStringType = 5, //!< string kNumberType = 6 //!< number }; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_RAPIDJSON_H_ osmium-tool-1.7.1/include/rapidjson/reader.h000066400000000000000000002336201315004223400210330ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_READER_H_ #define RAPIDJSON_READER_H_ /*! \file reader.h */ #include "allocators.h" #include "stream.h" #include "encodedstream.h" #include "internal/meta.h" #include "internal/stack.h" #include "internal/strtod.h" #include #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #include #pragma intrinsic(_BitScanForward) #endif #ifdef RAPIDJSON_SSE42 #include #elif defined(RAPIDJSON_SSE2) #include #endif #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4702) // unreachable code #endif #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(old-style-cast) RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) #endif #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define RAPIDJSON_NOTHING /* deliberately empty */ #ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \ RAPIDJSON_MULTILINEMACRO_END #endif #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) //!@endcond /*! \def RAPIDJSON_PARSE_ERROR_NORETURN \ingroup RAPIDJSON_ERRORS \brief Macro to indicate a parse error. \param parseErrorCode \ref rapidjson::ParseErrorCode of the error \param offset position of the error in JSON input (\c size_t) This macros can be used as a customization point for the internal error handling mechanism of RapidJSON. A common usage model is to throw an exception instead of requiring the caller to explicitly check the \ref rapidjson::GenericReader::Parse's return value: \code #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ throw ParseException(parseErrorCode, #parseErrorCode, offset) #include // std::runtime_error #include "rapidjson/error/error.h" // rapidjson::ParseResult struct ParseException : std::runtime_error, rapidjson::ParseResult { ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset) : std::runtime_error(msg), ParseResult(code, offset) {} }; #include "rapidjson/reader.h" \endcode \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse */ #ifndef RAPIDJSON_PARSE_ERROR_NORETURN #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ SetParseError(parseErrorCode, offset); \ RAPIDJSON_MULTILINEMACRO_END #endif /*! \def RAPIDJSON_PARSE_ERROR \ingroup RAPIDJSON_ERRORS \brief (Internal) macro to indicate and handle a parse error. \param parseErrorCode \ref rapidjson::ParseErrorCode of the error \param offset position of the error in JSON input (\c size_t) Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. \see RAPIDJSON_PARSE_ERROR_NORETURN \hideinitializer */ #ifndef RAPIDJSON_PARSE_ERROR #define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ RAPIDJSON_MULTILINEMACRO_END #endif #include "error/error.h" // ParseErrorCode, ParseResult RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // ParseFlag /*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS \ingroup RAPIDJSON_CONFIG \brief User-defined kParseDefaultFlags definition. User can define this as any \c ParseFlag combinations. */ #ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS #define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags #endif //! Combination of parseFlags /*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream */ enum ParseFlag { kParseNoFlags = 0, //!< No flags are set. kParseInsituFlag = 1, //!< In-situ(destructive) parsing. kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS }; /////////////////////////////////////////////////////////////////////////////// // Handler /*! \class rapidjson::Handler \brief Concept for receiving events from GenericReader upon parsing. The functions return true if no error occurs. If they return false, the event publisher should terminate the process. \code concept Handler { typename Ch; bool Null(); bool Bool(bool b); bool Int(int i); bool Uint(unsigned i); bool Int64(int64_t i); bool Uint64(uint64_t i); bool Double(double d); /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) bool RawNumber(const Ch* str, SizeType length, bool copy); bool String(const Ch* str, SizeType length, bool copy); bool StartObject(); bool Key(const Ch* str, SizeType length, bool copy); bool EndObject(SizeType memberCount); bool StartArray(); bool EndArray(SizeType elementCount); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // BaseReaderHandler //! Default implementation of Handler. /*! This can be used as base class of any reader handler. \note implements Handler concept */ template, typename Derived = void> struct BaseReaderHandler { typedef typename Encoding::Ch Ch; typedef typename internal::SelectIf, BaseReaderHandler, Derived>::Type Override; bool Default() { return true; } bool Null() { return static_cast(*this).Default(); } bool Bool(bool) { return static_cast(*this).Default(); } bool Int(int) { return static_cast(*this).Default(); } bool Uint(unsigned) { return static_cast(*this).Default(); } bool Int64(int64_t) { return static_cast(*this).Default(); } bool Uint64(uint64_t) { return static_cast(*this).Default(); } bool Double(double) { return static_cast(*this).Default(); } /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } bool String(const Ch*, SizeType, bool) { return static_cast(*this).Default(); } bool StartObject() { return static_cast(*this).Default(); } bool Key(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } bool EndObject(SizeType) { return static_cast(*this).Default(); } bool StartArray() { return static_cast(*this).Default(); } bool EndArray(SizeType) { return static_cast(*this).Default(); } }; /////////////////////////////////////////////////////////////////////////////// // StreamLocalCopy namespace internal { template::copyOptimization> class StreamLocalCopy; //! Do copy optimization. template class StreamLocalCopy { public: StreamLocalCopy(Stream& original) : s(original), original_(original) {} ~StreamLocalCopy() { original_ = s; } Stream s; private: StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; Stream& original_; }; //! Keep reference. template class StreamLocalCopy { public: StreamLocalCopy(Stream& original) : s(original) {} Stream& s; private: StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; }; } // namespace internal /////////////////////////////////////////////////////////////////////////////// // SkipWhitespace //! Skip the JSON white spaces in a stream. /*! \param is A input stream for skipping white spaces. \note This function has SSE2/SSE4.2 specialization. */ template void SkipWhitespace(InputStream& is) { internal::StreamLocalCopy copy(is); InputStream& s(copy.s); typename InputStream::Ch c; while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t') s.Take(); } inline const char* SkipWhitespace(const char* p, const char* end) { while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) ++p; return p; } #ifdef RAPIDJSON_SSE42 //! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { // Fast return for single non-whitespace if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // 16-byte align to the next boundary const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // The rest of string using SIMD static const char whitespace[16] = " \n\r\t"; const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); if (r != 0) { // some of characters is non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; _BitScanForward(&offset, r); return p + offset; #else return p + __builtin_ffs(r) - 1; #endif } } } inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { // Fast return for single non-whitespace if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) ++p; else return p; // The middle of string using SIMD static const char whitespace[16] = " \n\r\t"; const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); for (; p <= end - 16; p += 16) { const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); if (r != 0) { // some of characters is non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; _BitScanForward(&offset, r); return p + offset; #else return p + __builtin_ffs(r) - 1; #endif } } return SkipWhitespace(p, end); } #elif defined(RAPIDJSON_SSE2) //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { // Fast return for single non-whitespace if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // 16-byte align to the next boundary const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // The rest of string #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; #undef C16 const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); __m128i x = _mm_cmpeq_epi8(s, w0); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); unsigned short r = static_cast(~_mm_movemask_epi8(x)); if (r != 0) { // some of characters may be non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; _BitScanForward(&offset, r); return p + offset; #else return p + __builtin_ffs(r) - 1; #endif } } } inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { // Fast return for single non-whitespace if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) ++p; else return p; // The rest of string #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; #undef C16 const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); for (; p <= end - 16; p += 16) { const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); __m128i x = _mm_cmpeq_epi8(s, w0); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); unsigned short r = static_cast(~_mm_movemask_epi8(x)); if (r != 0) { // some of characters may be non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; _BitScanForward(&offset, r); return p + offset; #else return p + __builtin_ffs(r) - 1; #endif } } return SkipWhitespace(p, end); } #endif // RAPIDJSON_SSE2 #ifdef RAPIDJSON_SIMD //! Template function specialization for InsituStringStream template<> inline void SkipWhitespace(InsituStringStream& is) { is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); } //! Template function specialization for StringStream template<> inline void SkipWhitespace(StringStream& is) { is.src_ = SkipWhitespace_SIMD(is.src_); } template<> inline void SkipWhitespace(EncodedInputStream, MemoryStream>& is) { is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_); } #endif // RAPIDJSON_SIMD /////////////////////////////////////////////////////////////////////////////// // GenericReader //! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. /*! GenericReader parses JSON text from a stream, and send events synchronously to an object implementing Handler concept. It needs to allocate a stack for storing a single decoded string during non-destructive parsing. For in-situ parsing, the decoded string is directly written to the source text string, no temporary buffer is required. A GenericReader object can be reused for parsing multiple JSON text. \tparam SourceEncoding Encoding of the input stream. \tparam TargetEncoding Encoding of the parse output. \tparam StackAllocator Allocator type for stack. */ template class GenericReader { public: typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type //! Constructor. /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) */ GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {} //! Parse JSON text. /*! \tparam parseFlags Combination of \ref ParseFlag. \tparam InputStream Type of input stream, implementing Stream concept. \tparam Handler Type of handler, implementing Handler concept. \param is Input stream to be parsed. \param handler The handler to receive events. \return Whether the parsing is successful. */ template ParseResult Parse(InputStream& is, Handler& handler) { if (parseFlags & kParseIterativeFlag) return IterativeParse(is, handler); parseResult_.Clear(); ClearStackOnExit scope(*this); SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } else { ParseValue(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (!(parseFlags & kParseStopWhenDoneFlag)) { SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } } } return parseResult_; } //! Parse JSON text (with \ref kParseDefaultFlags) /*! \tparam InputStream Type of input stream, implementing Stream concept \tparam Handler Type of handler, implementing Handler concept. \param is Input stream to be parsed. \param handler The handler to receive events. \return Whether the parsing is successful. */ template ParseResult Parse(InputStream& is, Handler& handler) { return Parse(is, handler); } //! Whether a parse error has occured in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } //! Get the \ref ParseErrorCode of last parsing. ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } protected: void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); } private: // Prohibit copy constructor & assignment operator. GenericReader(const GenericReader&); GenericReader& operator=(const GenericReader&); void ClearStack() { stack_.Clear(); } // clear stack on any exit from ParseStream, e.g. due to exception struct ClearStackOnExit { explicit ClearStackOnExit(GenericReader& r) : r_(r) {} ~ClearStackOnExit() { r_.ClearStack(); } private: GenericReader& r_; ClearStackOnExit(const ClearStackOnExit&); ClearStackOnExit& operator=(const ClearStackOnExit&); }; template void SkipWhitespaceAndComments(InputStream& is) { SkipWhitespace(is); if (parseFlags & kParseCommentsFlag) { while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) { if (Consume(is, '*')) { while (true) { if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); else if (Consume(is, '*')) { if (Consume(is, '/')) break; } else is.Take(); } } else if (RAPIDJSON_LIKELY(Consume(is, '/'))) while (is.Peek() != '\0' && is.Take() != '\n'); else RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); SkipWhitespace(is); } } } // Parse object: { string : value, ... } template void ParseObject(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '{'); is.Take(); // Skip '{' if (RAPIDJSON_UNLIKELY(!handler.StartObject())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (Consume(is, '}')) { if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } for (SizeType memberCount = 0;;) { if (RAPIDJSON_UNLIKELY(is.Peek() != '"')) RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); ParseString(is, handler, true); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (RAPIDJSON_UNLIKELY(!Consume(is, ':'))) RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ParseValue(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++memberCount; switch (is.Peek()) { case ',': is.Take(); SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; break; case '}': is.Take(); if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy } if (parseFlags & kParseTrailingCommasFlag) { if (is.Peek() == '}') { if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); is.Take(); return; } } } } // Parse array: [ value, ... ] template void ParseArray(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '['); is.Take(); // Skip '[' if (RAPIDJSON_UNLIKELY(!handler.StartArray())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (Consume(is, ']')) { if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } for (SizeType elementCount = 0;;) { ParseValue(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++elementCount; SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (Consume(is, ',')) { SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; } else if (Consume(is, ']')) { if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } else RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); if (parseFlags & kParseTrailingCommasFlag) { if (is.Peek() == ']') { if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); is.Take(); return; } } } } template void ParseNull(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == 'n'); is.Take(); if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) { if (RAPIDJSON_UNLIKELY(!handler.Null())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template void ParseTrue(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == 't'); is.Take(); if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) { if (RAPIDJSON_UNLIKELY(!handler.Bool(true))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template void ParseFalse(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == 'f'); is.Take(); if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) { if (RAPIDJSON_UNLIKELY(!handler.Bool(false))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) { if (RAPIDJSON_LIKELY(is.Peek() == expect)) { is.Take(); return true; } else return false; } // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). template unsigned ParseHex4(InputStream& is, size_t escapeOffset) { unsigned codepoint = 0; for (int i = 0; i < 4; i++) { Ch c = is.Peek(); codepoint <<= 4; codepoint += static_cast(c); if (c >= '0' && c <= '9') codepoint -= '0'; else if (c >= 'A' && c <= 'F') codepoint -= 'A' - 10; else if (c >= 'a' && c <= 'f') codepoint -= 'a' - 10; else { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); } is.Take(); } return codepoint; } template class StackStream { public: typedef CharType Ch; StackStream(internal::Stack& stack) : stack_(stack), length_(0) {} RAPIDJSON_FORCEINLINE void Put(Ch c) { *stack_.template Push() = c; ++length_; } RAPIDJSON_FORCEINLINE void* Push(SizeType count) { length_ += count; return stack_.template Push(count); } size_t Length() const { return length_; } Ch* Pop() { return stack_.template Pop(length_); } private: StackStream(const StackStream&); StackStream& operator=(const StackStream&); internal::Stack& stack_; SizeType length_; }; // Parse string and generate String event. Different code paths for kParseInsituFlag. template void ParseString(InputStream& is, Handler& handler, bool isKey = false) { internal::StreamLocalCopy copy(is); InputStream& s(copy.s); RAPIDJSON_ASSERT(s.Peek() == '\"'); s.Take(); // Skip '\"' bool success = false; if (parseFlags & kParseInsituFlag) { typename InputStream::Ch *head = s.PutBegin(); ParseStringToStream(s, s); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; size_t length = s.PutEnd(head) - 1; RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); const typename TargetEncoding::Ch* const str = reinterpret_cast(head); success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); } else { StackStream stackStream(stack_); ParseStringToStream(s, stackStream); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SizeType length = static_cast(stackStream.Length()) - 1; const typename TargetEncoding::Ch* const str = stackStream.Pop(); success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); } if (RAPIDJSON_UNLIKELY(!success)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); } // Parse string to an output is // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. template RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 static const char escape[256] = { Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 }; #undef Z16 //!@endcond for (;;) { // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation. if (!(parseFlags & kParseValidateEncodingFlag)) ScanCopyUnescapedString(is, os); Ch c = is.Peek(); if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset is.Take(); Ch e = is.Peek(); if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) { is.Take(); os.Put(static_cast(escape[static_cast(e)])); } else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode is.Take(); unsigned codepoint = ParseHex4(is, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) { // Handle UTF-16 surrogate pair if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); unsigned codepoint2 = ParseHex4(is, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; } TEncoding::Encode(os, codepoint); } else RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset); } else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote is.Take(); os.Put('\0'); // null-terminate the string return; } else if (RAPIDJSON_UNLIKELY(static_cast(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF if (c == '\0') RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); else RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell()); } else { size_t offset = is.Tell(); if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? !Transcoder::Validate(is, os) : !Transcoder::Transcode(is, os)))) RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); } } } template static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) { // Do nothing for generic version } #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) // StringStream -> StackStream static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { const char* p = is.src_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = p; return; } else os.Put(*p++); // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped SizeType length; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; _BitScanForward(&offset, r); length = offset; #else length = static_cast(__builtin_ffs(r) - 1); #endif char* q = reinterpret_cast(os.Push(length)); for (size_t i = 0; i < length; i++) q[i] = p[i]; p += length; break; } _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); } is.src_ = p; } // InsituStringStream -> InsituStringStream static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { RAPIDJSON_ASSERT(&is == &os); (void)os; if (is.src_ == is.dst_) { SkipUnescapedString(is); return; } char* p = is.src_; char *q = is.dst_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = p; is.dst_ = q; return; } else *q++ = *p++; // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); for (;; p += 16, q += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped size_t length; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; _BitScanForward(&offset, r); length = offset; #else length = static_cast(__builtin_ffs(r) - 1); #endif for (const char* pend = p + length; p != pend; ) *q++ = *p++; break; } _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s); } is.src_ = p; is.dst_ = q; } // When read/write pointers are the same for insitu stream, just skip unescaped characters static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { RAPIDJSON_ASSERT(is.src_ == is.dst_); char* p = is.src_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); for (; p != nextAligned; p++) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = is.dst_ = p; return; } // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped size_t length; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; _BitScanForward(&offset, r); length = offset; #else length = static_cast(__builtin_ffs(r) - 1); #endif p += length; break; } } is.src_ = is.dst_ = p; } #endif template class NumberStream; template class NumberStream { public: typedef typename InputStream::Ch Ch; NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } ~NumberStream() {} RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } RAPIDJSON_FORCEINLINE void Push(char) {} size_t Tell() { return is.Tell(); } size_t Length() { return 0; } const char* Pop() { return 0; } protected: NumberStream& operator=(const NumberStream&); InputStream& is; }; template class NumberStream : public NumberStream { typedef NumberStream Base; public: NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} ~NumberStream() {} RAPIDJSON_FORCEINLINE Ch TakePush() { stackStream.Put(static_cast(Base::is.Peek())); return Base::is.Take(); } RAPIDJSON_FORCEINLINE void Push(char c) { stackStream.Put(c); } size_t Length() { return stackStream.Length(); } const char* Pop() { stackStream.Put('\0'); return stackStream.Pop(); } private: StackStream stackStream; }; template class NumberStream : public NumberStream { typedef NumberStream Base; public: NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} ~NumberStream() {} RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } }; template void ParseNumber(InputStream& is, Handler& handler) { internal::StreamLocalCopy copy(is); NumberStream s(*this, copy.s); size_t startOffset = s.Tell(); double d = 0.0; bool useNanOrInf = false; // Parse minus bool minus = Consume(s, '-'); // Parse int: zero / ( digit1-9 *DIGIT ) unsigned i = 0; uint64_t i64 = 0; bool use64bit = false; int significandDigit = 0; if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) { i = 0; s.TakePush(); } else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) { i = static_cast(s.TakePush() - '0'); if (minus) while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648 if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) { i64 = i; use64bit = true; break; } } i = i * 10 + static_cast(s.TakePush() - '0'); significandDigit++; } else while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295 if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) { i64 = i; use64bit = true; break; } } i = i * 10 + static_cast(s.TakePush() - '0'); significandDigit++; } } // Parse NaN or Infinity here else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { useNanOrInf = true; if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) { d = std::numeric_limits::quiet_NaN(); } else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) { d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); // Parse 64bit int bool useDouble = false; if (use64bit) { if (minus) while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { d = static_cast(i64); useDouble = true; break; } i64 = i64 * 10 + static_cast(s.TakePush() - '0'); significandDigit++; } else while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615 if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) { d = static_cast(i64); useDouble = true; break; } i64 = i64 * 10 + static_cast(s.TakePush() - '0'); significandDigit++; } } // Force double for big integer if (useDouble) { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0 RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); d = d * 10 + (s.TakePush() - '0'); } } // Parse frac = decimal-point 1*DIGIT int expFrac = 0; size_t decimalPosition; if (Consume(s, '.')) { decimalPosition = s.Length(); if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); if (!useDouble) { #if RAPIDJSON_64BIT // Use i64 to store significand in 64-bit architecture if (!use64bit) i64 = i; while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path break; else { i64 = i64 * 10 + static_cast(s.TakePush() - '0'); --expFrac; if (i64 != 0) significandDigit++; } } d = static_cast(i64); #else // Use double to store significand in 32-bit architecture d = static_cast(use64bit ? i64 : i); #endif useDouble = true; } while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (significandDigit < 17) { d = d * 10.0 + (s.TakePush() - '0'); --expFrac; if (RAPIDJSON_LIKELY(d > 0.0)) significandDigit++; } else s.TakePush(); } } else decimalPosition = s.Length(); // decimal position at the end of integer. // Parse exp = e [ minus / plus ] 1*DIGIT int exp = 0; if (Consume(s, 'e') || Consume(s, 'E')) { if (!useDouble) { d = static_cast(use64bit ? i64 : i); useDouble = true; } bool expMinus = false; if (Consume(s, '+')) ; else if (Consume(s, '-')) expMinus = true; if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = static_cast(s.Take() - '0'); if (expMinus) { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = exp * 10 + static_cast(s.Take() - '0'); if (exp >= 214748364) { // Issue #313: prevent overflow exponent while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent s.Take(); } } } else { // positive exp int maxExp = 308 - expFrac; while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = exp * 10 + static_cast(s.Take() - '0'); if (RAPIDJSON_UNLIKELY(exp > maxExp)) RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); } } } else RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); if (expMinus) exp = -exp; } // Finish parsing, call event according to the type of number. bool cont = true; if (parseFlags & kParseNumbersAsStringsFlag) { if (parseFlags & kParseInsituFlag) { s.Pop(); // Pop stack no matter if it will be used or not. typename InputStream::Ch* head = is.PutBegin(); const size_t length = s.Tell() - startOffset; RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); // unable to insert the \0 character here, it will erase the comma after this number const typename TargetEncoding::Ch* const str = reinterpret_cast(head); cont = handler.RawNumber(str, SizeType(length), false); } else { SizeType numCharsToCopy = static_cast(s.Length()); StringStream srcStream(s.Pop()); StackStream dstStream(stack_); while (numCharsToCopy--) { Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); } dstStream.Put('\0'); const typename TargetEncoding::Ch* str = dstStream.Pop(); const SizeType length = static_cast(dstStream.Length()) - 1; cont = handler.RawNumber(str, SizeType(length), true); } } else { size_t length = s.Length(); const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. if (useDouble) { int p = exp + expFrac; if (parseFlags & kParseFullPrecisionFlag) d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); else d = internal::StrtodNormalPrecision(d, p); cont = handler.Double(minus ? -d : d); } else if (useNanOrInf) { cont = handler.Double(d); } else { if (use64bit) { if (minus) cont = handler.Int64(static_cast(~i64 + 1)); else cont = handler.Uint64(i64); } else { if (minus) cont = handler.Int(static_cast(~i + 1)); else cont = handler.Uint(i); } } } if (RAPIDJSON_UNLIKELY(!cont)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset); } // Parse any JSON value template void ParseValue(InputStream& is, Handler& handler) { switch (is.Peek()) { case 'n': ParseNull (is, handler); break; case 't': ParseTrue (is, handler); break; case 'f': ParseFalse (is, handler); break; case '"': ParseString(is, handler); break; case '{': ParseObject(is, handler); break; case '[': ParseArray (is, handler); break; default : ParseNumber(is, handler); break; } } // Iterative Parsing // States enum IterativeParsingState { IterativeParsingStartState = 0, IterativeParsingFinishState, IterativeParsingErrorState, // Object states IterativeParsingObjectInitialState, IterativeParsingMemberKeyState, IterativeParsingKeyValueDelimiterState, IterativeParsingMemberValueState, IterativeParsingMemberDelimiterState, IterativeParsingObjectFinishState, // Array states IterativeParsingArrayInitialState, IterativeParsingElementState, IterativeParsingElementDelimiterState, IterativeParsingArrayFinishState, // Single value state IterativeParsingValueState }; enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 }; // Tokens enum Token { LeftBracketToken = 0, RightBracketToken, LeftCurlyBracketToken, RightCurlyBracketToken, CommaToken, ColonToken, StringToken, FalseToken, TrueToken, NullToken, NumberToken, kTokenCount }; RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) { //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define N NumberToken #define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N // Maps from ASCII to Token static const unsigned char tokenMap[256] = { N16, // 00~0F N16, // 10~1F N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F N16, // 40~4F N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF }; #undef N #undef N16 //!@endcond if (sizeof(Ch) == 1 || static_cast(c) < 256) return static_cast(tokenMap[static_cast(c)]); else return NumberToken; } RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { // current state x one lookahead token -> new state static const char G[cIterativeParsingStateCount][kTokenCount] = { // Start { IterativeParsingArrayInitialState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingValueState, // String IterativeParsingValueState, // False IterativeParsingValueState, // True IterativeParsingValueState, // Null IterativeParsingValueState // Number }, // Finish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // Error(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // ObjectInitial { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingObjectFinishState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingMemberKeyState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // MemberKey { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingKeyValueDelimiterState, // Colon IterativeParsingErrorState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // KeyValueDelimiter { IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) IterativeParsingErrorState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingMemberValueState, // String IterativeParsingMemberValueState, // False IterativeParsingMemberValueState, // True IterativeParsingMemberValueState, // Null IterativeParsingMemberValueState // Number }, // MemberValue { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingObjectFinishState, // Right curly bracket IterativeParsingMemberDelimiterState, // Comma IterativeParsingErrorState, // Colon IterativeParsingErrorState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // MemberDelimiter { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingObjectFinishState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingMemberKeyState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // ObjectFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // ArrayInitial { IterativeParsingArrayInitialState, // Left bracket(push Element state) IterativeParsingArrayFinishState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket(push Element state) IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingElementState, // String IterativeParsingElementState, // False IterativeParsingElementState, // True IterativeParsingElementState, // Null IterativeParsingElementState // Number }, // Element { IterativeParsingErrorState, // Left bracket IterativeParsingArrayFinishState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingErrorState, // Right curly bracket IterativeParsingElementDelimiterState, // Comma IterativeParsingErrorState, // Colon IterativeParsingErrorState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // ElementDelimiter { IterativeParsingArrayInitialState, // Left bracket(push Element state) IterativeParsingArrayFinishState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket(push Element state) IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingElementState, // String IterativeParsingElementState, // False IterativeParsingElementState, // True IterativeParsingElementState, // Null IterativeParsingElementState // Number }, // ArrayFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // Single Value (sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState } }; // End of G return static_cast(G[state][token]); } // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). // May return a new state on state pop. template RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { (void)token; switch (dst) { case IterativeParsingErrorState: return dst; case IterativeParsingObjectInitialState: case IterativeParsingArrayInitialState: { // Push the state(Element or MemeberValue) if we are nested in another array or value of member. // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. IterativeParsingState n = src; if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) n = IterativeParsingElementState; else if (src == IterativeParsingKeyValueDelimiterState) n = IterativeParsingMemberValueState; // Push current state. *stack_.template Push(1) = n; // Initialize and push the member/element count. *stack_.template Push(1) = 0; // Call handler bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); // On handler short circuits the parsing. if (!hr) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { is.Take(); return dst; } } case IterativeParsingMemberKeyState: ParseString(is, handler, true); if (HasParseError()) return IterativeParsingErrorState; else return dst; case IterativeParsingKeyValueDelimiterState: RAPIDJSON_ASSERT(token == ColonToken); is.Take(); return dst; case IterativeParsingMemberValueState: // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. ParseValue(is, handler); if (HasParseError()) { return IterativeParsingErrorState; } return dst; case IterativeParsingElementState: // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. ParseValue(is, handler); if (HasParseError()) { return IterativeParsingErrorState; } return dst; case IterativeParsingMemberDelimiterState: case IterativeParsingElementDelimiterState: is.Take(); // Update member/element count. *stack_.template Top() = *stack_.template Top() + 1; return dst; case IterativeParsingObjectFinishState: { // Transit from delimiter is only allowed when trailing commas are enabled if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell()); return IterativeParsingErrorState; } // Get member count. SizeType c = *stack_.template Pop(1); // If the object is not empty, count the last member. if (src == IterativeParsingMemberValueState) ++c; // Restore the state. IterativeParsingState n = static_cast(*stack_.template Pop(1)); // Transit to Finish state if this is the topmost scope. if (n == IterativeParsingStartState) n = IterativeParsingFinishState; // Call handler bool hr = handler.EndObject(c); // On handler short circuits the parsing. if (!hr) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { is.Take(); return n; } } case IterativeParsingArrayFinishState: { // Transit from delimiter is only allowed when trailing commas are enabled if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell()); return IterativeParsingErrorState; } // Get element count. SizeType c = *stack_.template Pop(1); // If the array is not empty, count the last element. if (src == IterativeParsingElementState) ++c; // Restore the state. IterativeParsingState n = static_cast(*stack_.template Pop(1)); // Transit to Finish state if this is the topmost scope. if (n == IterativeParsingStartState) n = IterativeParsingFinishState; // Call handler bool hr = handler.EndArray(c); // On handler short circuits the parsing. if (!hr) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { is.Take(); return n; } } default: // This branch is for IterativeParsingValueState actually. // Use `default:` rather than // `case IterativeParsingValueState:` is for code coverage. // The IterativeParsingStartState is not enumerated in this switch-case. // It is impossible for that case. And it can be caught by following assertion. // The IterativeParsingFinishState is not enumerated in this switch-case either. // It is a "derivative" state which cannot triggered from Predict() directly. // Therefore it cannot happen here. And it can be caught by following assertion. RAPIDJSON_ASSERT(dst == IterativeParsingValueState); // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. ParseValue(is, handler); if (HasParseError()) { return IterativeParsingErrorState; } return IterativeParsingFinishState; } } template void HandleError(IterativeParsingState src, InputStream& is) { if (HasParseError()) { // Error flag has been set. return; } switch (src) { case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; case IterativeParsingObjectInitialState: case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; case IterativeParsingKeyValueDelimiterState: case IterativeParsingArrayInitialState: case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; } } template ParseResult IterativeParse(InputStream& is, Handler& handler) { parseResult_.Clear(); ClearStackOnExit scope(*this); IterativeParsingState state = IterativeParsingStartState; SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); while (is.Peek() != '\0') { Token t = Tokenize(is.Peek()); IterativeParsingState n = Predict(state, t); IterativeParsingState d = Transit(state, t, n, is, handler); if (d == IterativeParsingErrorState) { HandleError(state, is); break; } state = d; // Do not further consume streams if a root JSON has been parsed. if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) break; SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } // Handle the end of file. if (state != IterativeParsingFinishState) HandleError(state, is); return parseResult_; } static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. ParseResult parseResult_; }; // class GenericReader //! Reader with UTF8 encoding and default allocator. typedef GenericReader, UTF8<> > Reader; RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #ifdef _MSC_VER RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_READER_H_ osmium-tool-1.7.1/include/rapidjson/schema.h000066400000000000000000002342161315004223400210330ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available-> // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License-> You may obtain a copy of the License at // // http://opensource->org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied-> See the License for the // specific language governing permissions and limitations under the License-> #ifndef RAPIDJSON_SCHEMA_H_ #define RAPIDJSON_SCHEMA_H_ #include "document.h" #include "pointer.h" #include // abs, floor #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 #else #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 #endif #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) #define RAPIDJSON_SCHEMA_USE_STDREGEX 1 #else #define RAPIDJSON_SCHEMA_USE_STDREGEX 0 #endif #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX #include "internal/regex.h" #elif RAPIDJSON_SCHEMA_USE_STDREGEX #include #endif #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX #define RAPIDJSON_SCHEMA_HAS_REGEX 1 #else #define RAPIDJSON_SCHEMA_HAS_REGEX 0 #endif #ifndef RAPIDJSON_SCHEMA_VERBOSE #define RAPIDJSON_SCHEMA_VERBOSE 0 #endif #if RAPIDJSON_SCHEMA_VERBOSE #include "stringbuffer.h" #endif RAPIDJSON_DIAG_PUSH #if defined(__GNUC__) RAPIDJSON_DIAG_OFF(effc++) #endif #ifdef __clang__ RAPIDJSON_DIAG_OFF(weak-vtables) RAPIDJSON_DIAG_OFF(exit-time-destructors) RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) RAPIDJSON_DIAG_OFF(variadic-macros) #endif #ifdef _MSC_VER RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Verbose Utilities #if RAPIDJSON_SCHEMA_VERBOSE namespace internal { inline void PrintInvalidKeyword(const char* keyword) { printf("Fail keyword: %s\n", keyword); } inline void PrintInvalidKeyword(const wchar_t* keyword) { wprintf(L"Fail keyword: %ls\n", keyword); } inline void PrintInvalidDocument(const char* document) { printf("Fail document: %s\n\n", document); } inline void PrintInvalidDocument(const wchar_t* document) { wprintf(L"Fail document: %ls\n\n", document); } inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) { printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d); } inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) { wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d); } } // namespace internal #endif // RAPIDJSON_SCHEMA_VERBOSE /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_INVALID_KEYWORD_RETURN #if RAPIDJSON_SCHEMA_VERBOSE #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) #else #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) #endif #define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\ RAPIDJSON_MULTILINEMACRO_BEGIN\ context.invalidKeyword = keyword.GetString();\ RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\ return false;\ RAPIDJSON_MULTILINEMACRO_END /////////////////////////////////////////////////////////////////////////////// // Forward declarations template class GenericSchemaDocument; namespace internal { template class Schema; /////////////////////////////////////////////////////////////////////////////// // ISchemaValidator class ISchemaValidator { public: virtual ~ISchemaValidator() {} virtual bool IsValid() const = 0; }; /////////////////////////////////////////////////////////////////////////////// // ISchemaStateFactory template class ISchemaStateFactory { public: virtual ~ISchemaStateFactory() {} virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0; virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; virtual void* CreateHasher() = 0; virtual uint64_t GetHashCode(void* hasher) = 0; virtual void DestroryHasher(void* hasher) = 0; virtual void* MallocState(size_t size) = 0; virtual void FreeState(void* p) = 0; }; /////////////////////////////////////////////////////////////////////////////// // Hasher // For comparison of compound value template class Hasher { public: typedef typename Encoding::Ch Ch; Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} bool Null() { return WriteType(kNullType); } bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } bool Int(int i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } bool Double(double d) { Number n; if (d < 0) n.u.i = static_cast(d); else n.u.u = static_cast(d); n.d = d; return WriteNumber(n); } bool RawNumber(const Ch* str, SizeType len, bool) { WriteBuffer(kNumberType, str, len * sizeof(Ch)); return true; } bool String(const Ch* str, SizeType len, bool) { WriteBuffer(kStringType, str, len * sizeof(Ch)); return true; } bool StartObject() { return true; } bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } bool EndObject(SizeType memberCount) { uint64_t h = Hash(0, kObjectType); uint64_t* kv = stack_.template Pop(memberCount * 2); for (SizeType i = 0; i < memberCount; i++) h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive *stack_.template Push() = h; return true; } bool StartArray() { return true; } bool EndArray(SizeType elementCount) { uint64_t h = Hash(0, kArrayType); uint64_t* e = stack_.template Pop(elementCount); for (SizeType i = 0; i < elementCount; i++) h = Hash(h, e[i]); // Use hash to achieve element order sensitive *stack_.template Push() = h; return true; } bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } uint64_t GetHashCode() const { RAPIDJSON_ASSERT(IsValid()); return *stack_.template Top(); } private: static const size_t kDefaultSize = 256; struct Number { union U { uint64_t u; int64_t i; }u; double d; }; bool WriteType(Type type) { return WriteBuffer(type, 0, 0); } bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); } bool WriteBuffer(Type type, const void* data, size_t len) { // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); const unsigned char* d = static_cast(data); for (size_t i = 0; i < len; i++) h = Hash(h, d[i]); *stack_.template Push() = h; return true; } static uint64_t Hash(uint64_t h, uint64_t d) { static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); h ^= d; h *= kPrime; return h; } Stack stack_; }; /////////////////////////////////////////////////////////////////////////////// // SchemaValidationContext template struct SchemaValidationContext { typedef Schema SchemaType; typedef ISchemaStateFactory SchemaValidatorFactoryType; typedef typename SchemaType::ValueType ValueType; typedef typename ValueType::Ch Ch; enum PatternValidatorType { kPatternValidatorOnly, kPatternValidatorWithProperty, kPatternValidatorWithAdditionalProperty }; SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) : factory(f), schema(s), valueSchema(), invalidKeyword(), hasher(), arrayElementHashCodes(), validators(), validatorCount(), patternPropertiesValidators(), patternPropertiesValidatorCount(), patternPropertiesSchemas(), patternPropertiesSchemaCount(), valuePatternValidatorType(kPatternValidatorOnly), propertyExist(), inArray(false), valueUniqueness(false), arrayUniqueness(false) { } ~SchemaValidationContext() { if (hasher) factory.DestroryHasher(hasher); if (validators) { for (SizeType i = 0; i < validatorCount; i++) factory.DestroySchemaValidator(validators[i]); factory.FreeState(validators); } if (patternPropertiesValidators) { for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) factory.DestroySchemaValidator(patternPropertiesValidators[i]); factory.FreeState(patternPropertiesValidators); } if (patternPropertiesSchemas) factory.FreeState(patternPropertiesSchemas); if (propertyExist) factory.FreeState(propertyExist); } SchemaValidatorFactoryType& factory; const SchemaType* schema; const SchemaType* valueSchema; const Ch* invalidKeyword; void* hasher; // Only validator access void* arrayElementHashCodes; // Only validator access this ISchemaValidator** validators; SizeType validatorCount; ISchemaValidator** patternPropertiesValidators; SizeType patternPropertiesValidatorCount; const SchemaType** patternPropertiesSchemas; SizeType patternPropertiesSchemaCount; PatternValidatorType valuePatternValidatorType; PatternValidatorType objectPatternValidatorType; SizeType arrayElementIndex; bool* propertyExist; bool inArray; bool valueUniqueness; bool arrayUniqueness; }; /////////////////////////////////////////////////////////////////////////////// // Schema template class Schema { public: typedef typename SchemaDocumentType::ValueType ValueType; typedef typename SchemaDocumentType::AllocatorType AllocatorType; typedef typename SchemaDocumentType::PointerType PointerType; typedef typename ValueType::EncodingType EncodingType; typedef typename EncodingType::Ch Ch; typedef SchemaValidationContext Context; typedef Schema SchemaType; typedef GenericValue SValue; friend class GenericSchemaDocument; Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : allocator_(allocator), enum_(), enumCount_(), not_(), type_((1 << kTotalSchemaType) - 1), // typeless validatorCount_(), properties_(), additionalPropertiesSchema_(), patternProperties_(), patternPropertyCount_(), propertyCount_(), minProperties_(), maxProperties_(SizeType(~0)), additionalProperties_(true), hasDependencies_(), hasRequired_(), hasSchemaDependencies_(), additionalItemsSchema_(), itemsList_(), itemsTuple_(), itemsTupleCount_(), minItems_(), maxItems_(SizeType(~0)), additionalItems_(true), uniqueItems_(false), pattern_(), minLength_(0), maxLength_(~SizeType(0)), exclusiveMinimum_(false), exclusiveMaximum_(false) { typedef typename SchemaDocumentType::ValueType ValueType; typedef typename ValueType::ConstValueIterator ConstValueIterator; typedef typename ValueType::ConstMemberIterator ConstMemberIterator; if (!value.IsObject()) return; if (const ValueType* v = GetMember(value, GetTypeString())) { type_ = 0; if (v->IsString()) AddType(*v); else if (v->IsArray()) for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) AddType(*itr); } if (const ValueType* v = GetMember(value, GetEnumString())) if (v->IsArray() && v->Size() > 0) { enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { typedef Hasher > EnumHasherType; char buffer[256 + 24]; MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); EnumHasherType h(&hasherAllocator, 256); itr->Accept(h); enum_[enumCount_++] = h.GetHashCode(); } } if (schemaDocument) { AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); } if (const ValueType* v = GetMember(value, GetNotString())) { schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); notValidatorIndex_ = validatorCount_; validatorCount_++; } // Object const ValueType* properties = GetMember(value, GetPropertiesString()); const ValueType* required = GetMember(value, GetRequiredString()); const ValueType* dependencies = GetMember(value, GetDependenciesString()); { // Gather properties from properties/required/dependencies SValue allProperties(kArrayType); if (properties && properties->IsObject()) for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) AddUniqueElement(allProperties, itr->name); if (required && required->IsArray()) for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) if (itr->IsString()) AddUniqueElement(allProperties, *itr); if (dependencies && dependencies->IsObject()) for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { AddUniqueElement(allProperties, itr->name); if (itr->value.IsArray()) for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) if (i->IsString()) AddUniqueElement(allProperties, *i); } if (allProperties.Size() > 0) { propertyCount_ = allProperties.Size(); properties_ = static_cast(allocator_->Malloc(sizeof(Property) * propertyCount_)); for (SizeType i = 0; i < propertyCount_; i++) { new (&properties_[i]) Property(); properties_[i].name = allProperties[i]; properties_[i].schema = GetTypeless(); } } } if (properties && properties->IsObject()) { PointerType q = p.Append(GetPropertiesString(), allocator_); for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { SizeType index; if (FindPropertyIndex(itr->name, &index)) schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document); } } if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { PointerType q = p.Append(GetPatternPropertiesString(), allocator_); patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); patternPropertyCount_ = 0; for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { new (&patternProperties_[patternPropertyCount_]) PatternProperty(); patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document); patternPropertyCount_++; } } if (required && required->IsArray()) for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) if (itr->IsString()) { SizeType index; if (FindPropertyIndex(*itr, &index)) { properties_[index].required = true; hasRequired_ = true; } } if (dependencies && dependencies->IsObject()) { PointerType q = p.Append(GetDependenciesString(), allocator_); hasDependencies_ = true; for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { SizeType sourceIndex; if (FindPropertyIndex(itr->name, &sourceIndex)) { if (itr->value.IsArray()) { properties_[sourceIndex].dependencies = static_cast(allocator_->Malloc(sizeof(bool) * propertyCount_)); std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) { SizeType targetIndex; if (FindPropertyIndex(*targetItr, &targetIndex)) properties_[sourceIndex].dependencies[targetIndex] = true; } } else if (itr->value.IsObject()) { hasSchemaDependencies_ = true; schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document); properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; validatorCount_++; } } } } if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) { if (v->IsBool()) additionalProperties_ = v->GetBool(); else if (v->IsObject()) schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document); } AssignIfExist(minProperties_, value, GetMinPropertiesString()); AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); // Array if (const ValueType* v = GetMember(value, GetItemsString())) { PointerType q = p.Append(GetItemsString(), allocator_); if (v->IsObject()) // List validation schemaDocument->CreateSchema(&itemsList_, q, *v, document); else if (v->IsArray()) { // Tuple validation itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema*) * v->Size())); SizeType index = 0; for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document); } } AssignIfExist(minItems_, value, GetMinItemsString()); AssignIfExist(maxItems_, value, GetMaxItemsString()); if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { if (v->IsBool()) additionalItems_ = v->GetBool(); else if (v->IsObject()) schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document); } AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); // String AssignIfExist(minLength_, value, GetMinLengthString()); AssignIfExist(maxLength_, value, GetMaxLengthString()); if (const ValueType* v = GetMember(value, GetPatternString())) pattern_ = CreatePattern(*v); // Number if (const ValueType* v = GetMember(value, GetMinimumString())) if (v->IsNumber()) minimum_.CopyFrom(*v, *allocator_); if (const ValueType* v = GetMember(value, GetMaximumString())) if (v->IsNumber()) maximum_.CopyFrom(*v, *allocator_); AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); if (const ValueType* v = GetMember(value, GetMultipleOfString())) if (v->IsNumber() && v->GetDouble() > 0.0) multipleOf_.CopyFrom(*v, *allocator_); } ~Schema() { if (allocator_) { allocator_->Free(enum_); } if (properties_) { for (SizeType i = 0; i < propertyCount_; i++) properties_[i].~Property(); AllocatorType::Free(properties_); } if (patternProperties_) { for (SizeType i = 0; i < patternPropertyCount_; i++) patternProperties_[i].~PatternProperty(); AllocatorType::Free(patternProperties_); } AllocatorType::Free(itemsTuple_); #if RAPIDJSON_SCHEMA_HAS_REGEX if (pattern_) { pattern_->~RegexType(); allocator_->Free(pattern_); } #endif } bool BeginValue(Context& context) const { if (context.inArray) { if (uniqueItems_) context.valueUniqueness = true; if (itemsList_) context.valueSchema = itemsList_; else if (itemsTuple_) { if (context.arrayElementIndex < itemsTupleCount_) context.valueSchema = itemsTuple_[context.arrayElementIndex]; else if (additionalItemsSchema_) context.valueSchema = additionalItemsSchema_; else if (additionalItems_) context.valueSchema = GetTypeless(); else RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); } else context.valueSchema = GetTypeless(); context.arrayElementIndex++; } return true; } RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { if (context.patternPropertiesValidatorCount > 0) { bool otherValid = false; SizeType count = context.patternPropertiesValidatorCount; if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) otherValid = context.patternPropertiesValidators[--count]->IsValid(); bool patternValid = true; for (SizeType i = 0; i < count; i++) if (!context.patternPropertiesValidators[i]->IsValid()) { patternValid = false; break; } if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { if (!patternValid) RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); } else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { if (!patternValid || !otherValid) RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); } else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty) RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); } if (enum_) { const uint64_t h = context.factory.GetHashCode(context.hasher); for (SizeType i = 0; i < enumCount_; i++) if (enum_[i] == h) goto foundEnum; RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString()); foundEnum:; } if (allOf_.schemas) for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) if (!context.validators[i]->IsValid()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString()); if (anyOf_.schemas) { for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) if (context.validators[i]->IsValid()) goto foundAny; RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); foundAny:; } if (oneOf_.schemas) { bool oneValid = false; for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) if (context.validators[i]->IsValid()) { if (oneValid) RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); else oneValid = true; } if (!oneValid) RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); } if (not_ && context.validators[notValidatorIndex_]->IsValid()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); return true; } bool Null(Context& context) const { if (!(type_ & (1 << kNullSchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); return CreateParallelValidator(context); } bool Bool(Context& context, bool) const { if (!(type_ & (1 << kBooleanSchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); return CreateParallelValidator(context); } bool Int(Context& context, int i) const { if (!CheckInt(context, i)) return false; return CreateParallelValidator(context); } bool Uint(Context& context, unsigned u) const { if (!CheckUint(context, u)) return false; return CreateParallelValidator(context); } bool Int64(Context& context, int64_t i) const { if (!CheckInt(context, i)) return false; return CreateParallelValidator(context); } bool Uint64(Context& context, uint64_t u) const { if (!CheckUint(context, u)) return false; return CreateParallelValidator(context); } bool Double(Context& context, double d) const { if (!(type_ & (1 << kNumberSchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) return false; if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) return false; if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) return false; return CreateParallelValidator(context); } bool String(Context& context, const Ch* str, SizeType length, bool) const { if (!(type_ & (1 << kStringSchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); if (minLength_ != 0 || maxLength_ != SizeType(~0)) { SizeType count; if (internal::CountStringCodePoint(str, length, &count)) { if (count < minLength_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); if (count > maxLength_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); } } if (pattern_ && !IsPatternMatch(pattern_, str, length)) RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); return CreateParallelValidator(context); } bool StartObject(Context& context) const { if (!(type_ & (1 << kObjectSchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); if (hasDependencies_ || hasRequired_) { context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); } if (patternProperties_) { // pre-allocate schema array SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType context.patternPropertiesSchemas = static_cast(context.factory.MallocState(sizeof(const SchemaType*) * count)); context.patternPropertiesSchemaCount = 0; std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); } return CreateParallelValidator(context); } bool Key(Context& context, const Ch* str, SizeType len, bool) const { if (patternProperties_) { context.patternPropertiesSchemaCount = 0; for (SizeType i = 0; i < patternPropertyCount_; i++) if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; } SizeType index; if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { if (context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; context.valueSchema = GetTypeless(); context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; } else context.valueSchema = properties_[index].schema; if (context.propertyExist) context.propertyExist[index] = true; return true; } if (additionalPropertiesSchema_) { if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; context.valueSchema = GetTypeless(); context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; } else context.valueSchema = additionalPropertiesSchema_; return true; } else if (additionalProperties_) { context.valueSchema = GetTypeless(); return true; } if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); return true; } bool EndObject(Context& context, SizeType memberCount) const { if (hasRequired_) for (SizeType index = 0; index < propertyCount_; index++) if (properties_[index].required) if (!context.propertyExist[index]) RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); if (memberCount < minProperties_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); if (memberCount > maxProperties_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); if (hasDependencies_) { for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) if (context.propertyExist[sourceIndex]) { if (properties_[sourceIndex].dependencies) { for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex]) RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); } else if (properties_[sourceIndex].dependenciesSchema) if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); } } return true; } bool StartArray(Context& context) const { if (!(type_ & (1 << kArraySchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); context.arrayElementIndex = 0; context.inArray = true; return CreateParallelValidator(context); } bool EndArray(Context& context, SizeType elementCount) const { context.inArray = false; if (elementCount < minItems_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); if (elementCount > maxItems_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); return true; } // Generate functions for string literal according to Ch #define RAPIDJSON_STRING_(name, ...) \ static const ValueType& Get##name##String() {\ static const Ch s[] = { __VA_ARGS__, '\0' };\ static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\ return v;\ } RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') RAPIDJSON_STRING_(Not, 'n', 'o', 't') RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') #undef RAPIDJSON_STRING_ private: enum SchemaValueType { kNullSchemaType, kBooleanSchemaType, kObjectSchemaType, kArraySchemaType, kStringSchemaType, kNumberSchemaType, kIntegerSchemaType, kTotalSchemaType }; #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX typedef internal::GenericRegex RegexType; #elif RAPIDJSON_SCHEMA_USE_STDREGEX typedef std::basic_regex RegexType; #else typedef char RegexType; #endif struct SchemaArray { SchemaArray() : schemas(), count() {} ~SchemaArray() { AllocatorType::Free(schemas); } const SchemaType** schemas; SizeType begin; // begin index of context.validators SizeType count; }; static const SchemaType* GetTypeless() { static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0); return &typeless; } template void AddUniqueElement(V1& a, const V2& v) { for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) if (*itr == v) return; V1 c(v, *allocator_); a.PushBack(c, *allocator_); } static const ValueType* GetMember(const ValueType& value, const ValueType& name) { typename ValueType::ConstMemberIterator itr = value.FindMember(name); return itr != value.MemberEnd() ? &(itr->value) : 0; } static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) { if (const ValueType* v = GetMember(value, name)) if (v->IsBool()) out = v->GetBool(); } static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) { if (const ValueType* v = GetMember(value, name)) if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) out = static_cast(v->GetUint64()); } void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) { if (const ValueType* v = GetMember(value, name)) { if (v->IsArray() && v->Size() > 0) { PointerType q = p.Append(name, allocator_); out.count = v->Size(); out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema*))); memset(out.schemas, 0, sizeof(Schema*)* out.count); for (SizeType i = 0; i < out.count; i++) schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document); out.begin = validatorCount_; validatorCount_ += out.count; } } } #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX template RegexType* CreatePattern(const ValueType& value) { if (value.IsString()) { RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString()); if (!r->IsValid()) { r->~RegexType(); AllocatorType::Free(r); r = 0; } return r; } return 0; } static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { return pattern->Search(str); } #elif RAPIDJSON_SCHEMA_USE_STDREGEX template RegexType* CreatePattern(const ValueType& value) { if (value.IsString()) try { return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); } catch (const std::regex_error&) { } return 0; } static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) { std::match_results r; return std::regex_search(str, str + length, r, *pattern); } #else template RegexType* CreatePattern(const ValueType&) { return 0; } static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } #endif // RAPIDJSON_SCHEMA_USE_STDREGEX void AddType(const ValueType& type) { if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); } bool CreateParallelValidator(Context& context) const { if (enum_ || context.arrayUniqueness) context.hasher = context.factory.CreateHasher(); if (validatorCount_) { RAPIDJSON_ASSERT(context.validators == 0); context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); context.validatorCount = validatorCount_; if (allOf_.schemas) CreateSchemaValidators(context, allOf_); if (anyOf_.schemas) CreateSchemaValidators(context, anyOf_); if (oneOf_.schemas) CreateSchemaValidators(context, oneOf_); if (not_) context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_); if (hasSchemaDependencies_) { for (SizeType i = 0; i < propertyCount_; i++) if (properties_[i].dependenciesSchema) context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema); } } return true; } void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const { for (SizeType i = 0; i < schemas.count; i++) context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]); } // O(n) bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const { SizeType len = name.GetStringLength(); const Ch* str = name.GetString(); for (SizeType index = 0; index < propertyCount_; index++) if (properties_[index].name.GetStringLength() == len && (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) { *outIndex = index; return true; } return false; } bool CheckInt(Context& context, int64_t i) const { if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); if (!minimum_.IsNull()) { if (minimum_.IsInt64()) { if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); } else if (minimum_.IsUint64()) { RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() } else if (!CheckDoubleMinimum(context, static_cast(i))) return false; } if (!maximum_.IsNull()) { if (maximum_.IsInt64()) { if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); } else if (maximum_.IsUint64()) /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64() else if (!CheckDoubleMaximum(context, static_cast(i))) return false; } if (!multipleOf_.IsNull()) { if (multipleOf_.IsUint64()) { if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); } else if (!CheckDoubleMultipleOf(context, static_cast(i))) return false; } return true; } bool CheckUint(Context& context, uint64_t i) const { if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); if (!minimum_.IsNull()) { if (minimum_.IsUint64()) { if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); } else if (minimum_.IsInt64()) /* do nothing */; // i >= 0 > minimum.Getint64() else if (!CheckDoubleMinimum(context, static_cast(i))) return false; } if (!maximum_.IsNull()) { if (maximum_.IsUint64()) { if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); } else if (maximum_.IsInt64()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_ else if (!CheckDoubleMaximum(context, static_cast(i))) return false; } if (!multipleOf_.IsNull()) { if (multipleOf_.IsUint64()) { if (i % multipleOf_.GetUint64() != 0) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); } else if (!CheckDoubleMultipleOf(context, static_cast(i))) return false; } return true; } bool CheckDoubleMinimum(Context& context, double d) const { if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); return true; } bool CheckDoubleMaximum(Context& context, double d) const { if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); return true; } bool CheckDoubleMultipleOf(Context& context, double d) const { double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); double q = std::floor(a / b); double r = a - q * b; if (r > 0.0) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); return true; } struct Property { Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} ~Property() { AllocatorType::Free(dependencies); } SValue name; const SchemaType* schema; const SchemaType* dependenciesSchema; SizeType dependenciesValidatorIndex; bool* dependencies; bool required; }; struct PatternProperty { PatternProperty() : schema(), pattern() {} ~PatternProperty() { if (pattern) { pattern->~RegexType(); AllocatorType::Free(pattern); } } const SchemaType* schema; RegexType* pattern; }; AllocatorType* allocator_; uint64_t* enum_; SizeType enumCount_; SchemaArray allOf_; SchemaArray anyOf_; SchemaArray oneOf_; const SchemaType* not_; unsigned type_; // bitmask of kSchemaType SizeType validatorCount_; SizeType notValidatorIndex_; Property* properties_; const SchemaType* additionalPropertiesSchema_; PatternProperty* patternProperties_; SizeType patternPropertyCount_; SizeType propertyCount_; SizeType minProperties_; SizeType maxProperties_; bool additionalProperties_; bool hasDependencies_; bool hasRequired_; bool hasSchemaDependencies_; const SchemaType* additionalItemsSchema_; const SchemaType* itemsList_; const SchemaType** itemsTuple_; SizeType itemsTupleCount_; SizeType minItems_; SizeType maxItems_; bool additionalItems_; bool uniqueItems_; RegexType* pattern_; SizeType minLength_; SizeType maxLength_; SValue minimum_; SValue maximum_; SValue multipleOf_; bool exclusiveMinimum_; bool exclusiveMaximum_; }; template struct TokenHelper { RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { *documentStack.template Push() = '/'; char buffer[21]; size_t length = static_cast((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); for (size_t i = 0; i < length; i++) *documentStack.template Push() = buffer[i]; } }; // Partial specialized version for char to prevent buffer copying. template struct TokenHelper { RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { if (sizeof(SizeType) == 4) { char *buffer = documentStack.template Push(1 + 10); // '/' + uint *buffer++ = '/'; const char* end = internal::u32toa(index, buffer); documentStack.template Pop(static_cast(10 - (end - buffer))); } else { char *buffer = documentStack.template Push(1 + 20); // '/' + uint64 *buffer++ = '/'; const char* end = internal::u64toa(index, buffer); documentStack.template Pop(static_cast(20 - (end - buffer))); } } }; } // namespace internal /////////////////////////////////////////////////////////////////////////////// // IGenericRemoteSchemaDocumentProvider template class IGenericRemoteSchemaDocumentProvider { public: typedef typename SchemaDocumentType::Ch Ch; virtual ~IGenericRemoteSchemaDocumentProvider() {} virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; }; /////////////////////////////////////////////////////////////////////////////// // GenericSchemaDocument //! JSON schema document. /*! A JSON schema document is a compiled version of a JSON schema. It is basically a tree of internal::Schema. \note This is an immutable class (i.e. its instance cannot be modified after construction). \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. \tparam Allocator Allocator type for allocating memory of this document. */ template class GenericSchemaDocument { public: typedef ValueT ValueType; typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProviderType; typedef Allocator AllocatorType; typedef typename ValueType::EncodingType EncodingType; typedef typename EncodingType::Ch Ch; typedef internal::Schema SchemaType; typedef GenericPointer PointerType; friend class internal::Schema; template friend class GenericSchemaValidator; //! Constructor. /*! Compile a JSON document into schema document. \param document A JSON document as source. \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. \param allocator An optional allocator instance for allocating memory. Can be null. */ explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : remoteProvider_(remoteProvider), allocator_(allocator), ownAllocator_(), root_(), schemaMap_(allocator, kInitialSchemaMapSize), schemaRef_(allocator, kInitialSchemaRefSize) { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); // Generate root schema, it will call CreateSchema() to create sub-schemas, // And call AddRefSchema() if there are $ref. CreateSchemaRecursive(&root_, PointerType(), document, document); // Resolve $ref while (!schemaRef_.Empty()) { SchemaRefEntry* refEntry = schemaRef_.template Pop(1); if (const SchemaType* s = GetSchema(refEntry->target)) { if (refEntry->schema) *refEntry->schema = s; // Create entry in map if not exist if (!GetSchema(refEntry->source)) { new (schemaMap_.template Push()) SchemaEntry(refEntry->source, const_cast(s), false, allocator_); } } refEntry->~SchemaRefEntry(); } RAPIDJSON_ASSERT(root_ != 0); schemaRef_.ShrinkToFit(); // Deallocate all memory for ref } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT : remoteProvider_(rhs.remoteProvider_), allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), root_(rhs.root_), schemaMap_(std::move(rhs.schemaMap_)), schemaRef_(std::move(rhs.schemaRef_)) { rhs.remoteProvider_ = 0; rhs.allocator_ = 0; rhs.ownAllocator_ = 0; } #endif //! Destructor ~GenericSchemaDocument() { while (!schemaMap_.Empty()) schemaMap_.template Pop(1)->~SchemaEntry(); RAPIDJSON_DELETE(ownAllocator_); } //! Get the root schema. const SchemaType& GetRoot() const { return *root_; } private: //! Prohibit copying GenericSchemaDocument(const GenericSchemaDocument&); //! Prohibit assignment GenericSchemaDocument& operator=(const GenericSchemaDocument&); struct SchemaRefEntry { SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} PointerType source; PointerType target; const SchemaType** schema; }; struct SchemaEntry { SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} ~SchemaEntry() { if (owned) { schema->~SchemaType(); Allocator::Free(schema); } } PointerType pointer; SchemaType* schema; bool owned; }; void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { if (schema) *schema = SchemaType::GetTypeless(); if (v.GetType() == kObjectType) { const SchemaType* s = GetSchema(pointer); if (!s) CreateSchema(schema, pointer, v, document); for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); } else if (v.GetType() == kArrayType) for (SizeType i = 0; i < v.Size(); i++) CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document); } void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { RAPIDJSON_ASSERT(pointer.IsValid()); if (v.IsObject()) { if (!HandleRefSchema(pointer, schema, v, document)) { SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_); new (schemaMap_.template Push()) SchemaEntry(pointer, s, true, allocator_); if (schema) *schema = s; } } } bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) { static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' }; static const ValueType kRefValue(kRefString, 4); typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue); if (itr == v.MemberEnd()) return false; if (itr->value.IsString()) { SizeType len = itr->value.GetStringLength(); if (len > 0) { const Ch* s = itr->value.GetString(); SizeType i = 0; while (i < len && s[i] != '#') // Find the first # i++; if (i > 0) { // Remote reference, resolve immediately if (remoteProvider_) { if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) { PointerType pointer(&s[i], len - i, allocator_); if (pointer.IsValid()) { if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { if (schema) *schema = sc; return true; } } } } } else if (s[i] == '#') { // Local reference, defer resolution PointerType pointer(&s[i], len - i, allocator_); if (pointer.IsValid()) { if (const ValueType* nv = pointer.Get(document)) if (HandleRefSchema(source, schema, *nv, document)) return true; new (schemaRef_.template Push()) SchemaRefEntry(source, pointer, schema, allocator_); return true; } } } } return false; } const SchemaType* GetSchema(const PointerType& pointer) const { for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) if (pointer == target->pointer) return target->schema; return 0; } PointerType GetPointer(const SchemaType* schema) const { for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) if (schema == target->schema) return target->pointer; return PointerType(); } static const size_t kInitialSchemaMapSize = 64; static const size_t kInitialSchemaRefSize = 64; IRemoteSchemaDocumentProviderType* remoteProvider_; Allocator *allocator_; Allocator *ownAllocator_; const SchemaType* root_; //!< Root schema. internal::Stack schemaMap_; // Stores created Pointer -> Schemas internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref }; //! GenericSchemaDocument using Value type. typedef GenericSchemaDocument SchemaDocument; //! IGenericRemoteSchemaDocumentProvider using SchemaDocument. typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; /////////////////////////////////////////////////////////////////////////////// // GenericSchemaValidator //! JSON Schema Validator. /*! A SAX style JSON schema validator. It uses a \c GenericSchemaDocument to validate SAX events. It delegates the incoming SAX events to an output handler. The default output handler does nothing. It can be reused multiple times by calling \c Reset(). \tparam SchemaDocumentType Type of schema document. \tparam OutputHandler Type of output handler. Default handler does nothing. \tparam StateAllocator Allocator for storing the internal validation states. */ template < typename SchemaDocumentType, typename OutputHandler = BaseReaderHandler, typename StateAllocator = CrtAllocator> class GenericSchemaValidator : public internal::ISchemaStateFactory, public internal::ISchemaValidator { public: typedef typename SchemaDocumentType::SchemaType SchemaType; typedef typename SchemaDocumentType::PointerType PointerType; typedef typename SchemaType::EncodingType EncodingType; typedef typename EncodingType::Ch Ch; //! Constructor without output handler. /*! \param schemaDocument The schema document to conform to. \param allocator Optional allocator for storing internal validation states. \param schemaStackCapacity Optional initial capacity of schema path stack. \param documentStackCapacity Optional initial capacity of document path stack. */ GenericSchemaValidator( const SchemaDocumentType& schemaDocument, StateAllocator* allocator = 0, size_t schemaStackCapacity = kDefaultSchemaStackCapacity, size_t documentStackCapacity = kDefaultDocumentStackCapacity) : schemaDocument_(&schemaDocument), root_(schemaDocument.GetRoot()), outputHandler_(GetNullHandler()), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) #endif { } //! Constructor with output handler. /*! \param schemaDocument The schema document to conform to. \param allocator Optional allocator for storing internal validation states. \param schemaStackCapacity Optional initial capacity of schema path stack. \param documentStackCapacity Optional initial capacity of document path stack. */ GenericSchemaValidator( const SchemaDocumentType& schemaDocument, OutputHandler& outputHandler, StateAllocator* allocator = 0, size_t schemaStackCapacity = kDefaultSchemaStackCapacity, size_t documentStackCapacity = kDefaultDocumentStackCapacity) : schemaDocument_(&schemaDocument), root_(schemaDocument.GetRoot()), outputHandler_(outputHandler), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) #endif { } //! Destructor. ~GenericSchemaValidator() { Reset(); RAPIDJSON_DELETE(ownStateAllocator_); } //! Reset the internal states. void Reset() { while (!schemaStack_.Empty()) PopSchema(); documentStack_.Clear(); valid_ = true; } //! Checks whether the current state is valid. // Implementation of ISchemaValidator virtual bool IsValid() const { return valid_; } //! Gets the JSON pointer pointed to the invalid schema. PointerType GetInvalidSchemaPointer() const { return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema()); } //! Gets the keyword of invalid schema. const Ch* GetInvalidSchemaKeyword() const { return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword; } //! Gets the JSON pointer pointed to the invalid value. PointerType GetInvalidDocumentPointer() const { return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); } #if RAPIDJSON_SCHEMA_VERBOSE #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ RAPIDJSON_MULTILINEMACRO_BEGIN\ *documentStack_.template Push() = '\0';\ documentStack_.template Pop(1);\ internal::PrintInvalidDocument(documentStack_.template Bottom());\ RAPIDJSON_MULTILINEMACRO_END #else #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() #endif #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ if (!valid_) return false; \ if (!BeginValue() || !CurrentSchema().method arg1) {\ RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ return valid_ = false;\ } #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ for (Context* context = schemaStack_.template Bottom(); context != schemaStack_.template End(); context++) {\ if (context->hasher)\ static_cast(context->hasher)->method arg2;\ if (context->validators)\ for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ static_cast(context->validators[i_])->method arg2;\ if (context->patternPropertiesValidators)\ for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ static_cast(context->patternPropertiesValidators[i_])->method arg2;\ } #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ return valid_ = EndValue() && outputHandler_.method arg2 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); } bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } bool RawNumber(const Ch* str, SizeType length, bool copy) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } bool String(const Ch* str, SizeType length, bool copy) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } bool StartObject() { RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); return valid_ = outputHandler_.StartObject(); } bool Key(const Ch* str, SizeType len, bool copy) { if (!valid_) return false; AppendToken(str, len); if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); return valid_ = outputHandler_.Key(str, len, copy); } bool EndObject(SizeType memberCount) { if (!valid_) return false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); } bool StartArray() { RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); return valid_ = outputHandler_.StartArray(); } bool EndArray(SizeType elementCount) { if (!valid_) return false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); } #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ // Implementation of ISchemaStateFactory virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) { return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, #if RAPIDJSON_SCHEMA_VERBOSE depth_ + 1, #endif &GetStateAllocator()); } virtual void DestroySchemaValidator(ISchemaValidator* validator) { GenericSchemaValidator* v = static_cast(validator); v->~GenericSchemaValidator(); StateAllocator::Free(v); } virtual void* CreateHasher() { return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); } virtual uint64_t GetHashCode(void* hasher) { return static_cast(hasher)->GetHashCode(); } virtual void DestroryHasher(void* hasher) { HasherType* h = static_cast(hasher); h->~HasherType(); StateAllocator::Free(h); } virtual void* MallocState(size_t size) { return GetStateAllocator().Malloc(size); } virtual void FreeState(void* p) { return StateAllocator::Free(p); } private: typedef typename SchemaType::Context Context; typedef GenericValue, StateAllocator> HashCodeArray; typedef internal::Hasher HasherType; GenericSchemaValidator( const SchemaDocumentType& schemaDocument, const SchemaType& root, #if RAPIDJSON_SCHEMA_VERBOSE unsigned depth, #endif StateAllocator* allocator = 0, size_t schemaStackCapacity = kDefaultSchemaStackCapacity, size_t documentStackCapacity = kDefaultDocumentStackCapacity) : schemaDocument_(&schemaDocument), root_(root), outputHandler_(GetNullHandler()), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(depth) #endif { } StateAllocator& GetStateAllocator() { if (!stateAllocator_) stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator()); return *stateAllocator_; } bool BeginValue() { if (schemaStack_.Empty()) PushSchema(root_); else { if (CurrentContext().inArray) internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); if (!CurrentSchema().BeginValue(CurrentContext())) return false; SizeType count = CurrentContext().patternPropertiesSchemaCount; const SchemaType** sa = CurrentContext().patternPropertiesSchemas; typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; bool valueUniqueness = CurrentContext().valueUniqueness; if (CurrentContext().valueSchema) PushSchema(*CurrentContext().valueSchema); if (count > 0) { CurrentContext().objectPatternValidatorType = patternValidatorType; ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; va = static_cast(MallocState(sizeof(ISchemaValidator*) * count)); for (SizeType i = 0; i < count; i++) va[validatorCount++] = CreateSchemaValidator(*sa[i]); } CurrentContext().arrayUniqueness = valueUniqueness; } return true; } bool EndValue() { if (!CurrentSchema().EndValue(CurrentContext())) return false; #if RAPIDJSON_SCHEMA_VERBOSE GenericStringBuffer sb; schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); *documentStack_.template Push() = '\0'; documentStack_.template Pop(1); internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom()); #endif uint64_t h = CurrentContext().arrayUniqueness ? static_cast(CurrentContext().hasher)->GetHashCode() : 0; PopSchema(); if (!schemaStack_.Empty()) { Context& context = CurrentContext(); if (context.valueUniqueness) { HashCodeArray* a = static_cast(context.arrayElementHashCodes); if (!a) CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) if (itr->GetUint64() == h) RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString()); a->PushBack(h, GetStateAllocator()); } } // Remove the last token of document pointer while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/') ; return true; } void AppendToken(const Ch* str, SizeType len) { documentStack_.template Reserve(1 + len * 2); // worst case all characters are escaped as two characters *documentStack_.template PushUnsafe() = '/'; for (SizeType i = 0; i < len; i++) { if (str[i] == '~') { *documentStack_.template PushUnsafe() = '~'; *documentStack_.template PushUnsafe() = '0'; } else if (str[i] == '/') { *documentStack_.template PushUnsafe() = '~'; *documentStack_.template PushUnsafe() = '1'; } else *documentStack_.template PushUnsafe() = str[i]; } } RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, &schema); } RAPIDJSON_FORCEINLINE void PopSchema() { Context* c = schemaStack_.template Pop(1); if (HashCodeArray* a = static_cast(c->arrayElementHashCodes)) { a->~HashCodeArray(); StateAllocator::Free(a); } c->~Context(); } const SchemaType& CurrentSchema() const { return *schemaStack_.template Top()->schema; } Context& CurrentContext() { return *schemaStack_.template Top(); } const Context& CurrentContext() const { return *schemaStack_.template Top(); } static OutputHandler& GetNullHandler() { static OutputHandler nullHandler; return nullHandler; } static const size_t kDefaultSchemaStackCapacity = 1024; static const size_t kDefaultDocumentStackCapacity = 256; const SchemaDocumentType* schemaDocument_; const SchemaType& root_; OutputHandler& outputHandler_; StateAllocator* stateAllocator_; StateAllocator* ownStateAllocator_; internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch) bool valid_; #if RAPIDJSON_SCHEMA_VERBOSE unsigned depth_; #endif }; typedef GenericSchemaValidator SchemaValidator; /////////////////////////////////////////////////////////////////////////////// // SchemaValidatingReader //! A helper class for parsing with validation. /*! This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). \tparam parseFlags Combination of \ref ParseFlag. \tparam InputStream Type of input stream, implementing Stream concept. \tparam SourceEncoding Encoding of the input stream. \tparam SchemaDocumentType Type of schema document. \tparam StackAllocator Allocator type for stack. */ template < unsigned parseFlags, typename InputStream, typename SourceEncoding, typename SchemaDocumentType = SchemaDocument, typename StackAllocator = CrtAllocator> class SchemaValidatingReader { public: typedef typename SchemaDocumentType::PointerType PointerType; typedef typename InputStream::Ch Ch; //! Constructor /*! \param is Input stream. \param sd Schema document. */ SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {} template bool operator()(Handler& handler) { GenericReader reader; GenericSchemaValidator validator(sd_, handler); parseResult_ = reader.template Parse(is_, validator); isValid_ = validator.IsValid(); if (isValid_) { invalidSchemaPointer_ = PointerType(); invalidSchemaKeyword_ = 0; invalidDocumentPointer_ = PointerType(); } else { invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); } return parseResult_; } const ParseResult& GetParseResult() const { return parseResult_; } bool IsValid() const { return isValid_; } const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } private: InputStream& is_; const SchemaDocumentType& sd_; ParseResult parseResult_; PointerType invalidSchemaPointer_; const Ch* invalidSchemaKeyword_; PointerType invalidDocumentPointer_; bool isValid_; }; RAPIDJSON_NAMESPACE_END RAPIDJSON_DIAG_POP #endif // RAPIDJSON_SCHEMA_H_ osmium-tool-1.7.1/include/rapidjson/stream.h000066400000000000000000000125321315004223400210610ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #include "rapidjson.h" #ifndef RAPIDJSON_STREAM_H_ #define RAPIDJSON_STREAM_H_ #include "encodings.h" RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Stream /*! \class rapidjson::Stream \brief Concept for reading and writing characters. For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). For write-only stream, only need to implement Put() and Flush(). \code concept Stream { typename Ch; //!< Character type of the stream. //! Read the current character from stream without moving the read cursor. Ch Peek() const; //! Read the current character from stream and moving the read cursor to next character. Ch Take(); //! Get the current read cursor. //! \return Number of characters read from start. size_t Tell(); //! Begin writing operation at the current read pointer. //! \return The begin writer pointer. Ch* PutBegin(); //! Write a character. void Put(Ch c); //! Flush the buffer. void Flush(); //! End the writing operation. //! \param begin The begin write pointer returned by PutBegin(). //! \return Number of characters written. size_t PutEnd(Ch* begin); } \endcode */ //! Provides additional information for stream. /*! By using traits pattern, this type provides a default configuration for stream. For custom stream, this type can be specialized for other configuration. See TEST(Reader, CustomStringStream) in readertest.cpp for example. */ template struct StreamTraits { //! Whether to make local copy of stream for optimization during parsing. /*! By default, for safety, streams do not use local copy optimization. Stream that can be copied fast should specialize this, like StreamTraits. */ enum { copyOptimization = 0 }; }; //! Reserve n characters for writing to a stream. template inline void PutReserve(Stream& stream, size_t count) { (void)stream; (void)count; } //! Write character to a stream, presuming buffer is reserved. template inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { stream.Put(c); } //! Put N copies of a character to a stream. template inline void PutN(Stream& stream, Ch c, size_t n) { PutReserve(stream, n); for (size_t i = 0; i < n; i++) PutUnsafe(stream, c); } /////////////////////////////////////////////////////////////////////////////// // StringStream //! Read-only string stream. /*! \note implements Stream concept */ template struct GenericStringStream { typedef typename Encoding::Ch Ch; GenericStringStream(const Ch *src) : src_(src), head_(src) {} Ch Peek() const { return *src_; } Ch Take() { return *src_++; } size_t Tell() const { return static_cast(src_ - head_); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } const Ch* src_; //!< Current read position. const Ch* head_; //!< Original head of the string. }; template struct StreamTraits > { enum { copyOptimization = 1 }; }; //! String stream with UTF8 encoding. typedef GenericStringStream > StringStream; /////////////////////////////////////////////////////////////////////////////// // InsituStringStream //! A read-write string stream. /*! This string stream is particularly designed for in-situ parsing. \note implements Stream concept */ template struct GenericInsituStringStream { typedef typename Encoding::Ch Ch; GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} // Read Ch Peek() { return *src_; } Ch Take() { return *src_++; } size_t Tell() { return static_cast(src_ - head_); } // Write void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } Ch* PutBegin() { return dst_ = src_; } size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } void Flush() {} Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } void Pop(size_t count) { dst_ -= count; } Ch* src_; Ch* dst_; Ch* head_; }; template struct StreamTraits > { enum { copyOptimization = 1 }; }; //! Insitu string stream with UTF8 encoding. typedef GenericInsituStringStream > InsituStringStream; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_STREAM_H_ osmium-tool-1.7.1/include/rapidjson/stringbuffer.h000066400000000000000000000073261315004223400222730ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_STRINGBUFFER_H_ #define RAPIDJSON_STRINGBUFFER_H_ #include "stream.h" #include "internal/stack.h" #if RAPIDJSON_HAS_CXX11_RVALUE_REFS #include // std::move #endif #include "internal/stack.h" #if defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(c++98-compat) #endif RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory output stream. /*! \tparam Encoding Encoding of the stream. \tparam Allocator type for allocating memory buffer. \note implements Stream concept */ template class GenericStringBuffer { public: typedef typename Encoding::Ch Ch; GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { if (&rhs != this) stack_ = std::move(rhs.stack_); return *this; } #endif void Put(Ch c) { *stack_.template Push() = c; } void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } void Flush() {} void Clear() { stack_.Clear(); } void ShrinkToFit() { // Push and pop a null terminator. This is safe. *stack_.template Push() = '\0'; stack_.ShrinkToFit(); stack_.template Pop(1); } void Reserve(size_t count) { stack_.template Reserve(count); } Ch* Push(size_t count) { return stack_.template Push(count); } Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } void Pop(size_t count) { stack_.template Pop(count); } const Ch* GetString() const { // Push and pop a null terminator. This is safe. *stack_.template Push() = '\0'; stack_.template Pop(1); return stack_.template Bottom(); } size_t GetSize() const { return stack_.GetSize(); } static const size_t kDefaultCapacity = 256; mutable internal::Stack stack_; private: // Prohibit copy constructor & assignment operator. GenericStringBuffer(const GenericStringBuffer&); GenericStringBuffer& operator=(const GenericStringBuffer&); }; //! String buffer with UTF8 encoding typedef GenericStringBuffer > StringBuffer; template inline void PutReserve(GenericStringBuffer& stream, size_t count) { stream.Reserve(count); } template inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { stream.PutUnsafe(c); } //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { std::memset(stream.stack_.Push(n), c, n * sizeof(c)); } RAPIDJSON_NAMESPACE_END #if defined(__clang__) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_STRINGBUFFER_H_ osmium-tool-1.7.1/include/rapidjson/writer.h000066400000000000000000000553351315004223400211120ustar00rootroot00000000000000// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_WRITER_H_ #define RAPIDJSON_WRITER_H_ #include "stream.h" #include "internal/stack.h" #include "internal/strfunc.h" #include "internal/dtoa.h" #include "internal/itoa.h" #include "stringbuffer.h" #include // placement new #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #include #pragma intrinsic(_BitScanForward) #endif #ifdef RAPIDJSON_SSE42 #include #elif defined(RAPIDJSON_SSE2) #include #endif #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #endif #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(unreachable-code) #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // WriteFlag /*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS \ingroup RAPIDJSON_CONFIG \brief User-defined kWriteDefaultFlags definition. User can define this as any \c WriteFlag combinations. */ #ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS #define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags #endif //! Combination of writeFlags enum WriteFlag { kWriteNoFlags = 0, //!< No flags are set. kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS }; //! JSON writer /*! Writer implements the concept Handler. It generates JSON text by events to an output os. User may programmatically calls the functions of a writer to generate JSON text. On the other side, a writer can also be passed to objects that generates events, for example Reader::Parse() and Document::Accept(). \tparam OutputStream Type of output stream. \tparam SourceEncoding Encoding of source string. \tparam TargetEncoding Encoding of output stream. \tparam StackAllocator Type of allocator for allocating memory of stack. \note implements Handler concept */ template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> class Writer { public: typedef typename SourceEncoding::Ch Ch; static const int kDefaultMaxDecimalPlaces = 324; //! Constructor /*! \param os Output stream. \param stackAllocator User supplied allocator. If it is null, it will create a private one. \param levelDepth Initial capacity of stack. */ explicit Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} explicit Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} //! Reset the writer with a new stream. /*! This function reset the writer with a new stream and default settings, in order to make a Writer object reusable for output multiple JSONs. \param os New output stream. \code Writer writer(os1); writer.StartObject(); // ... writer.EndObject(); writer.Reset(os2); writer.StartObject(); // ... writer.EndObject(); \endcode */ void Reset(OutputStream& os) { os_ = &os; hasRoot_ = false; level_stack_.Clear(); } //! Checks whether the output is a complete JSON. /*! A complete JSON has a complete root object or array. */ bool IsComplete() const { return hasRoot_ && level_stack_.Empty(); } int GetMaxDecimalPlaces() const { return maxDecimalPlaces_; } //! Sets the maximum number of decimal places for double output. /*! This setting truncates the output with specified number of decimal places. For example, \code writer.SetMaxDecimalPlaces(3); writer.StartArray(); writer.Double(0.12345); // "0.123" writer.Double(0.0001); // "0.0" writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent) writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent) writer.EndArray(); \endcode The default setting does not truncate any decimal places. You can restore to this setting by calling \code writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); \endcode */ void SetMaxDecimalPlaces(int maxDecimalPlaces) { maxDecimalPlaces_ = maxDecimalPlaces; } /*!@name Implementation of Handler \see Handler */ //@{ bool Null() { Prefix(kNullType); return EndValue(WriteNull()); } bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); } bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); } bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } //! Writes the given \c double value to the stream /*! \param d The value to be written. \return Whether it is succeed. */ bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); } bool RawNumber(const Ch* str, SizeType length, bool copy = false) { (void)copy; Prefix(kNumberType); return EndValue(WriteString(str, length)); } bool String(const Ch* str, SizeType length, bool copy = false) { (void)copy; Prefix(kStringType); return EndValue(WriteString(str, length)); } #if RAPIDJSON_HAS_STDSTRING bool String(const std::basic_string& str) { return String(str.data(), SizeType(str.size())); } #endif bool StartObject() { Prefix(kObjectType); new (level_stack_.template Push()) Level(false); return WriteStartObject(); } bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); level_stack_.template Pop(1); return EndValue(WriteEndObject()); } bool StartArray() { Prefix(kArrayType); new (level_stack_.template Push()) Level(true); return WriteStartArray(); } bool EndArray(SizeType elementCount = 0) { (void)elementCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); level_stack_.template Pop(1); return EndValue(WriteEndArray()); } //@} /*! @name Convenience extensions */ //@{ //! Simpler but slower overload. bool String(const Ch* str) { return String(str, internal::StrLen(str)); } bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } //@} //! Write a raw JSON value. /*! For user to write a stringified JSON as a value. \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. \param length Length of the json. \param type Type of the root of json. */ bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); } protected: //! Information for each nested level struct Level { Level(bool inArray_) : valueCount(0), inArray(inArray_) {} size_t valueCount; //!< number of values in this level bool inArray; //!< true if in array, otherwise in object }; static const size_t kDefaultLevelDepth = 32; bool WriteNull() { PutReserve(*os_, 4); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; } bool WriteBool(bool b) { if (b) { PutReserve(*os_, 4); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); } else { PutReserve(*os_, 5); PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); } return true; } bool WriteInt(int i) { char buffer[11]; const char* end = internal::i32toa(i, buffer); PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteUint(unsigned u) { char buffer[10]; const char* end = internal::u32toa(u, buffer); PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteInt64(int64_t i64) { char buffer[21]; const char* end = internal::i64toa(i64, buffer); PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteUint64(uint64_t u64) { char buffer[20]; char* end = internal::u64toa(u64, buffer); PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteDouble(double d) { if (internal::Double(d).IsNanOrInf()) { if (!(writeFlags & kWriteNanAndInfFlag)) return false; if (internal::Double(d).IsNan()) { PutReserve(*os_, 3); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); return true; } if (internal::Double(d).Sign()) { PutReserve(*os_, 9); PutUnsafe(*os_, '-'); } else PutReserve(*os_, 8); PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); return true; } char buffer[25]; char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteString(const Ch* str, SizeType length) { static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static const char escape[256] = { #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //0 1 2 3 4 5 6 7 8 9 A B C D E F 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 Z16, Z16, // 30~4F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF #undef Z16 }; if (TargetEncoding::supportUnicode) PutReserve(*os_, 2 + length * 6); // "\uxxxx..." else PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." PutUnsafe(*os_, '\"'); GenericStringStream is(str); while (ScanWriteUnescapedString(is, length)) { const Ch c = is.Peek(); if (!TargetEncoding::supportUnicode && static_cast(c) >= 0x80) { // Unicode escaping unsigned codepoint; if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) return false; PutUnsafe(*os_, '\\'); PutUnsafe(*os_, 'u'); if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); } else { RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); // Surrogate pair unsigned s = codepoint - 0x010000; unsigned lead = (s >> 10) + 0xD800; unsigned trail = (s & 0x3FF) + 0xDC00; PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); PutUnsafe(*os_, hexDigits[(lead ) & 15]); PutUnsafe(*os_, '\\'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); PutUnsafe(*os_, hexDigits[(trail ) & 15]); } } else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast(c)])) { is.Take(); PutUnsafe(*os_, '\\'); PutUnsafe(*os_, static_cast(escape[static_cast(c)])); if (escape[static_cast(c)] == 'u') { PutUnsafe(*os_, '0'); PutUnsafe(*os_, '0'); PutUnsafe(*os_, hexDigits[static_cast(c) >> 4]); PutUnsafe(*os_, hexDigits[static_cast(c) & 0xF]); } } else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? Transcoder::Validate(is, *os_) : Transcoder::TranscodeUnsafe(is, *os_)))) return false; } PutUnsafe(*os_, '\"'); return true; } bool ScanWriteUnescapedString(GenericStringStream& is, size_t length) { return RAPIDJSON_LIKELY(is.Tell() < length); } bool WriteStartObject() { os_->Put('{'); return true; } bool WriteEndObject() { os_->Put('}'); return true; } bool WriteStartArray() { os_->Put('['); return true; } bool WriteEndArray() { os_->Put(']'); return true; } bool WriteRawValue(const Ch* json, size_t length) { PutReserve(*os_, length); for (size_t i = 0; i < length; i++) { RAPIDJSON_ASSERT(json[i] != '\0'); PutUnsafe(*os_, json[i]); } return true; } void Prefix(Type type) { (void)type; if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root Level* level = level_stack_.template Top(); if (level->valueCount > 0) { if (level->inArray) os_->Put(','); // add comma if it is not the first element in array else // in object os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); } if (!level->inArray && level->valueCount % 2 == 0) RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name level->valueCount++; } else { RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. hasRoot_ = true; } } // Flush the value if it is the top level one. bool EndValue(bool ret) { if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text os_->Flush(); return ret; } OutputStream* os_; internal::Stack level_stack_; int maxDecimalPlaces_; bool hasRoot_; private: // Prohibit copy constructor & assignment operator. Writer(const Writer&); Writer& operator=(const Writer&); }; // Full specialization for StringStream to prevent memory copying template<> inline bool Writer::WriteInt(int i) { char *buffer = os_->Push(11); const char* end = internal::i32toa(i, buffer); os_->Pop(static_cast(11 - (end - buffer))); return true; } template<> inline bool Writer::WriteUint(unsigned u) { char *buffer = os_->Push(10); const char* end = internal::u32toa(u, buffer); os_->Pop(static_cast(10 - (end - buffer))); return true; } template<> inline bool Writer::WriteInt64(int64_t i64) { char *buffer = os_->Push(21); const char* end = internal::i64toa(i64, buffer); os_->Pop(static_cast(21 - (end - buffer))); return true; } template<> inline bool Writer::WriteUint64(uint64_t u) { char *buffer = os_->Push(20); const char* end = internal::u64toa(u, buffer); os_->Pop(static_cast(20 - (end - buffer))); return true; } template<> inline bool Writer::WriteDouble(double d) { if (internal::Double(d).IsNanOrInf()) { // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) return false; if (internal::Double(d).IsNan()) { PutReserve(*os_, 3); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); return true; } if (internal::Double(d).Sign()) { PutReserve(*os_, 9); PutUnsafe(*os_, '-'); } else PutReserve(*os_, 8); PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); return true; } char *buffer = os_->Push(25); char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); os_->Pop(static_cast(25 - (end - buffer))); return true; } #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) template<> inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { if (length < 16) return RAPIDJSON_LIKELY(is.Tell() < length); if (!RAPIDJSON_LIKELY(is.Tell() < length)) return false; const char* p = is.src_; const char* end = is.head_ + length; const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); if (nextAligned > end) return true; while (p != nextAligned) if (*p < 0x20 || *p == '\"' || *p == '\\') { is.src_ = p; return RAPIDJSON_LIKELY(is.Tell() < length); } else os_->PutUnsafe(*p++); // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); for (; p != endAligned; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped SizeType len; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; _BitScanForward(&offset, r); len = offset; #else len = static_cast(__builtin_ffs(r) - 1); #endif char* q = reinterpret_cast(os_->PushUnsafe(len)); for (size_t i = 0; i < len; i++) q[i] = p[i]; p += len; break; } _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); } is.src_ = p; return RAPIDJSON_LIKELY(is.Tell() < length); } #endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) RAPIDJSON_NAMESPACE_END #ifdef _MSC_VER RAPIDJSON_DIAG_POP #endif #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_RAPIDJSON_H_ osmium-tool-1.7.1/iwyu.imp000066400000000000000000000024531315004223400155060ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # Configuration for Include-What-You-Use tool # # http://include-what-you-use.org/ # #----------------------------------------------------------------------------- [ { "include": ["", "private", "", "public"] }, { "include": ["", "private", "", "public"] }, { "include": ["", "private", "", "public"] }, { "include": ["", "private", "", "public"] }, { "include": ["", "private", "", "public"] }, { "include": ["", "private", "", "public"] }, { "include": ["", "private", "", "public"] }, { "include": ["", "public", "", "private"] }, { "include": ["", "private", "", "public"] } ] osmium-tool-1.7.1/man/000077500000000000000000000000001315004223400145515ustar00rootroot00000000000000osmium-tool-1.7.1/man/CMakeLists.txt000066400000000000000000000060561315004223400173200ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # Optional "man" target to generate man pages # #----------------------------------------------------------------------------- message(STATUS "Looking for pandoc") find_program(PANDOC pandoc) function(add_man_page _section _name) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/man${_section}) set(_output_file ${CMAKE_CURRENT_BINARY_DIR}/man${_section}/${_name}.${_section}) set(_source_file ${CMAKE_CURRENT_SOURCE_DIR}/${_name}.md) set(_dest_file ${CMAKE_BINARY_DIR}/man-source/${_name}.md) file(READ ${CMAKE_CURRENT_SOURCE_DIR}/common-options.md MAN_COMMON_OPTIONS) file(READ ${CMAKE_CURRENT_SOURCE_DIR}/progress-options.md MAN_PROGRESS_OPTIONS) file(READ ${CMAKE_CURRENT_SOURCE_DIR}/input-options.md MAN_INPUT_OPTIONS) file(READ ${CMAKE_CURRENT_SOURCE_DIR}/output-options.md MAN_OUTPUT_OPTIONS) file(READ ${CMAKE_SOURCE_DIR}/export-example-config/default-config.json EXPORT_DEFAULT_CONFIG) configure_file(${_source_file} ${_dest_file} @ONLY) string(TOUPPER ${_name} _name_upcase) add_custom_command(OUTPUT ${_output_file} COMMAND ${PANDOC} ${PANDOC_MAN_OPTIONS} --variable "title=${_name_upcase}" --variable "section=${_section}" -o ${_output_file} ${_dest_file} DEPENDS ${_source_file} manpage.template common-options.md input-options.md output-options.md WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Building manpage ${_name}.${_section}" VERBATIM) set(ALL_MAN_PAGES "${ALL_MAN_PAGES};${_output_file}" PARENT_SCOPE) endfunction() if(PANDOC) message(STATUS "Looking for pandoc - found") message(STATUS " Manual pages will be built") set(PANDOC_MAN_OPTIONS -s -t man --template ${CMAKE_CURRENT_SOURCE_DIR}/manpage.template --variable "description=osmium/${OSMIUM_VERSION}" --variable "version=${OSMIUM_VERSION}" --variable "author=${AUTHOR}" ) set(PANDOC_HTML_OPTIONS -s -t html) add_man_page(1 osmium) add_man_page(1 osmium-add-locations-to-ways) add_man_page(1 osmium-apply-changes) add_man_page(1 osmium-cat) add_man_page(1 osmium-changeset-filter) add_man_page(1 osmium-check-refs) add_man_page(1 osmium-derive-changes) add_man_page(1 osmium-diff) add_man_page(1 osmium-export) add_man_page(1 osmium-extract) add_man_page(1 osmium-fileinfo) add_man_page(1 osmium-getid) add_man_page(1 osmium-merge) add_man_page(1 osmium-merge-changes) add_man_page(1 osmium-renumber) add_man_page(1 osmium-show) add_man_page(1 osmium-sort) add_man_page(1 osmium-tags-filter) add_man_page(1 osmium-time-filter) add_man_page(5 osmium-file-formats) add_man_page(5 osmium-index-types) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DESTINATION share) add_custom_target(man ALL DEPENDS ${ALL_MAN_PAGES}) else() message(STATUS "Looking for pandoc - not found") message(STATUS " Manual pages will not be built") endif() osmium-tool-1.7.1/man/common-options.md000066400000000000000000000002421315004223400200520ustar00rootroot00000000000000 # COMMON OPTIONS -h, --help : Show usage help. -v, --verbose : Set verbose mode. The program will output information about what it is doing to STDERR. osmium-tool-1.7.1/man/input-options.md000066400000000000000000000005431315004223400177250ustar00rootroot00000000000000 # INPUT OPTIONS -F, --input-format=FORMAT : The format of the input file(s). Can be used to set the input format if it can't be autodetected from the file name(s). This will set the format for all input files, there is no way to set the format for some input files only. See **osmium-file-formats**(5) or the libosmium manual for details. osmium-tool-1.7.1/man/manpage.template000066400000000000000000000012741315004223400177220ustar00rootroot00000000000000$if(has-tables)$ .\"t $endif$ .TH "$title$" "$section$" "$version$" "$footer$" "$header$" $for(header-includes)$ $header-includes$ $endfor$ $for(include-before)$ $include-before$ $endfor$ $body$ $for(include-after)$ $include-after$ $endfor$ $if(author)$ .SH COPYRIGHT .PP Copyright (C) 2013\-2017 Jochen Topf . License GPLv3+: GNU GPL version 3 or later . This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. .SH CONTACT .PP If you have any questions or want to report a bug, please go to http://osmcode.org/contact.html .SH AUTHORS $for(author)$$author$$sep$; $endfor$. $endif$ osmium-tool-1.7.1/man/osmium-add-locations-to-ways.md000066400000000000000000000062561315004223400225350ustar00rootroot00000000000000 # NAME osmium-add-locations-to-ways - add node locations to ways in OSM file # SYNOPSIS **osmium add-locations-to-ways** \[*OPTIONS*\] *OSM-FILE*... # DESCRIPTION Usually only nodes have locations and the ways refer to those locations via the IDs of the nodes. This program will copy the input file(s) to the output, taking the locations from the nodes and adding them to the ways. This makes it easier for other programs to assemble the way geometries. The input file must contain all nodes needed for the ways, otherwise there will be an error. You can change this behaviour using the `--ignore-missing-nodes` option. Nodes without any tags will not be copied (unless the **--keep-untagged-nodes**, **-n** option is used). The size of the output file will be similar or a bit smaller than the input file (unless the **--keep-untagged-nodes**, **-n** option is used in which case it will be a lot bigger). Note that the OSM files generated by this command use a non-standard format extension. The **osmium add-locations-to-ways** command has to keep an index of the node locations in memory or in a temporary file on disk while doing its work. There are several different ways it can do that which have different advantages and disadvantages. The default is good enough for most cases, but see the **osmium-index-types**(5) man page for details. If the **--keep-untagged-nodes**, **-n** option is used, files created by this command can be updated with the **apply-changes** command using the **--locations-on-ways** option. This command will not work on full history files. This commands reads its input file(s) only once and writes its output file in one go so it can be streamed, ie. it can read from STDIN and write to STDOUT. # OPTIONS -i, --index-type=TYPE : Set the index type. For details see the **osmium-index-types**(5) man page. -I, --show-index-types : Shows a list of available index types. For details see the **osmium-index-types**(5) man page. -n, --keep-untagged-nodes : Keep the untagged nodes in the output file. --ignore-missing-nodes : If this is not set a missing node needed for a way results in an error. If this is set, errors are ignored and the way will have an invalid location set for the missing node. @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_OPTIONS@ @MAN_INPUT_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # DIAGNOSTICS **osmium add-locations-to-ways** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium add-locations-to-ways** will usually keep all node locations in memory. For larger data files, this can need several tens of GBytes of memory. See the **osmium-index-types**(5) man page for details. # EXAMPLES Add node locations to an extract keeping all nodes: osmium add-locations-to-ways -n -o germany-low.osm.pbf germany.osm.pbf Add node locations to a planet file (without untagged nodes): osmium add-locations-to-ways -i dense_mmap_array -o planet-low.osm.pbf planet.osm.pbf # SEE ALSO * **osmium**(1), **osmium-file-formats**(5), **osmium-index-types**(5) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-apply-changes.md000066400000000000000000000064711315004223400211450ustar00rootroot00000000000000 # NAME osmium-apply-changes - apply OSM change file(s) to OSM data file # SYNOPSIS **osmium apply-changes** \[*OPTIONS*\] *OSM-DATA-FILE* *OSM-CHANGE-FILE*... **osmium apply-changes** \[*OPTIONS*\] *OSM-HISTORY-FILE* *OSM-CHANGE-FILE*... # DESCRIPTION Merges the content of all OSM change files and applies those changes to the OSM data or history file. Objects in the data or history file must be sorted by type, ID, and version. Objects in change files need not be sorted, so it doesn't matter in what order the change files are given or in what order they contain the data. Changes can be applied to normal OSM data files or OSM history files with this command. File formats will be autodetected from the file name suffixes, see the **--with-history** option if that doesn't work. This commands reads its input file(s) only once and writes its output file in one go so it can be streamed, ie. it can read from STDIN and write to STDOUT. # OPTIONS -H, --with-history : Update an OSM history file (instead of a normal OSM data file). Both input and output must be history files. This option is usually not necessary, because history files will be detected from their file name suffixes, but if this detection doesn't work, you can force this mode with this option. Can not be used together with the **--locations-on-ways** option. --locations-on-ways : Input has and output should have node locations on ways. Can be used to update files created by the **osmium-add-locations-to-ways**. See there for details on the format. Can not be used together with the **--with-history**,**-H** option. -r, --remove-deleted : Deprecated. Remove deleted objects from the output. This is now the default if your input file is a normal OSM data file ('.osm'). -s, --simplify : Deprecated. Only write the last version of any object to the output. This is now the default if your input file is a normal OSM data file ('.osm'). @MAN_COMMON_OPTIONS@ # INPUT OPTIONS -F, --input-format=FORMAT : The format of the OSM-DATA-FILE or OSM-HISTORY-FILE. Can be used to set the input format if it can't be autodetected from the file name. See **osmium-file-formats**(5) or the libosmium manual for details. --change-file-format=FORMAT : The format of the OSM-CHANGE-FILE(s). Can be used to set the input format if it can't be autodetected from the file name(s). This will set the format for all change files, there is no way to set the format for some change files only. See **osmium-file-formats**(5) or the libosmium manual for details. @MAN_OUTPUT_OPTIONS@ # DIAGNOSTICS **osmium apply-changes** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium apply-changes** keeps the contents of all the change files in main memory. This will take roughly 10 times as much memory as the files take on disk in *.osm.bz2* format. # EXAMPLES Apply changes in `362.osc.gz` to planet file and write result to `new.osm.pbf`: osmium apply-changes --output=new.osm.pbf planet.osm.pbf 362.osc.gz # SEE ALSO * **osmium**(1), **osmium-file-formats**(5), **osmium-merge-changes**(1), **osmium-derive-changes**(1) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-cat.md000066400000000000000000000031361315004223400171540ustar00rootroot00000000000000 # NAME osmium-cat - concatenate OSM files and convert to different formats # SYNOPSIS **osmium cat** \[*OPTIONS*\] *OSM-FILE*... # DESCRIPTION Concatenates all input files and writes the result to the output file. The data is not sorted in any way but strictly copied from input to output. Because this program supports several different input and output formats, it can be used to convert OSM files from one format into another. This commands reads its input file(s) only once and writes its output file in one go so it can be streamed, ie. it can read from STDIN and write to STDOUT. # OPTIONS -t, --object-type=TYPE : Read only objects of given type (*node*, *way*, *relation*, *changeset*). By default all types are read. This option can be given multiple times. @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_OPTIONS@ @MAN_INPUT_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # DIAGNOSTICS **osmium cat** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium cat** does all its work on the fly and doesn't keep much data in main memory. # EXAMPLES Convert a PBF file to a compressed XML file: osmium cat -o out.osm.bz2 in.osm.pbf Concatenate all change files in the 'changes' directory into one: osmium cat -o all-changes.osc.gz changes/*.osc.gz Copy nodes and ways from source to destination file: osmium cat -o dest.osm.pbf source.osm.pbf -t node -t way # SEE ALSO * **osmium**(1), **osmium-file-formats**(5) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-changeset-filter.md000066400000000000000000000041161315004223400216300ustar00rootroot00000000000000 # NAME osmium-changeset-filter - filter changesets from OSM changeset file # SYNOPSIS **osmium changeset-filter** \[*OPTIONS*\] *OSM-CHANGESET-FILE* # DESCRIPTION Copy the changesets matching all the given criteria to the output. Matching criteria are given through command line options. This commands reads its input file only once and writes its output file in one go so it can be streamed, ie. it can read from STDIN and write to STDOUT. # FILTER OPTIONS -a, --after=TIMESTAMP : Only copy changesets closed after the given time. This will always include all open changesets. -b, --before=TIMESTAMP : Only copy changesets created before the given time. -B, --bbox=LEFT,BOTTOM,RIGHT,TOP : Only copy changesets with a bounding box overlapping the specified box. -c, --with-changes : Only copy changesets with changes. -C, --without-changes : Only copy changesets without changes. -d, --with-discussion : Only copy changesets with discussions, ie changesets with at least one comment. -D, --without-discussion : Only copy changesets without discussions, ie changesets without any comments. --open : Only copy open changesets. --closed : Only copy closed changesets. -u, --user=USER : Only copy changesets by the given user name. -U, --uid=UID : Only copy changesets by the given user ID. @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_OPTIONS@ @MAN_INPUT_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # DIAGNOSTICS **osmium changeset-filter** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium changeset-filter** does all its work on the fly and doesn't keep much data in main memory. # EXAMPLES To see all changesets by user "foo": osmium changeset-filter -u foo -f debug changesets.osm.bz2 To create an OPL file containing only open changesets: osmium changeset-filter --open -o open-changesets.opl.bz2 changesets.osm.bz2 # SEE ALSO * **osmium**(1), **osmium-file-formats**(5) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-check-refs.md000066400000000000000000000041731315004223400204210ustar00rootroot00000000000000 # NAME osmium-check-refs - check referential integrity of OSM file # SYNOPSIS **osmium check-refs** \[*OPTIONS*\] *OSM-DATA-FILE* # DESCRIPTION Ways in OSM files refer to OSM nodes; relations refer to nodes, ways, or other relations. This command checks whether all objects *referenced* in the input file are also *present* in the input file. Referential integrity is often broken in extracts. This can lead to problems with some uses of the OSM data. Use this command to make sure your data is good. If the option -r is not given, this command will only check if all nodes referenced in ways are in the file, with the option, relations will also be checked. This command expects the input file to be ordered in the usual way: First nodes in order of ID, then ways in order of ID, then relations in order of ID. Negative IDs are allowed, they must be ordered before the positive IDs. See the **osmium-sort**(1) man page for details of the ordering. This command will only work for OSM data files, not OSM history files or change files. This commands reads its input file only once, ie. it can read from STDIN. # OPTIONS -i, --show-ids : Print all missing IDs to STDOUT. If you don't specify this option, only a summary is shown. -r, --check-relations : Also check referential integrity of relations. Without this option, only nodes in ways are checked. @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_OPTIONS@ @MAN_INPUT_OPTIONS@ # MEMORY USAGE **osmium check-refs** will do the check in one pass through the input data. It needs enough main memory to store all temporary data. Largest memory need will be about 1 bit for each node ID, that's roughly 540 MB these days (Summer 2017). With the **-r**, **--check-relations** option memory use will be a bit bigger. # DIAGNOSTICS **osmium check-refs** exits with exit code 0 ~ if all references are satisfied 1 ~ if there was an error processing the data or some references were not satisfied, or 2 ~ if there was a problem with the command line arguments. # SEE ALSO * **osmium**(1), **osmium-file-formats**(5), **osmium-sort**(1) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-derive-changes.md000066400000000000000000000063361315004223400212760ustar00rootroot00000000000000 # NAME osmium-derive-changes - create OSM change files from two OSM data files # SYNOPSIS **osmium derive-changes** \[*OPTIONS*\] *OSM-FILE1* *OSM-FILE2* # DESCRIPTION Finds differences between two OSM files and creates a change file with those differences. The resulting change file is created in a way, that it could be applied on *OSM-FILE1* to re-create *OSM-FILE2*. Objects in both input files must be sorted by type, ID, and version. The first input file must be from a point in time before the second input file. Only object type, id, and version are compared, so this program will not detect differences in, say, the tags, unless the object has a new version, which is the normal way things work in OSM. If you need to compare all data in OSM files, have a look at the **osmium diff** program. For this command to create a proper change file you have to set the **--output** option or **--output-format** option in a way that it will generate an .osc file, typically by using something like '-o out.osc.gz'. You can create any other OSM file format, but that is usually not what you want. Osmium derive-changes will warn you in this case. Note that for objects that are in *OSM-FILE1* but not *OSM-FILE2* a "deleted" entry will be created in the output. But because we can not know when this deletion actually occurred, in which changeset, and by which user, it is unclear what attributes this deleted object should have. Also, if you are working with extracts, the object might not actually have been deleted in the OSM database, but just moved out of the extract you are looking at. So a real, new, "deleted" version was never created. Usually the "deleted" object will get the same version number and timestamp as the object in *OSM-FILE1* had, all other information will be removed. But you can change this using the **--increment-version**, **--keep-details**, and **--update-timestamp** options. Depending on which software you are using the change files with, different settings might be necessary. This commands reads its input files only once and writes its output file in one go so it can be streamed, ie. it can read from STDIN and write to STDOUT. # OPTIONS --increment-version : Increment version number of deleted objects. --keep-details : Keep details of deleted objects. Usually only id, version, and timestamp are kept. If this option is set all attributes, all tags, and all nodes or members for ways and relations, respectively, are kept. --update-timestamp : Update timestamp of deleted objects to the current time. This is the same behaviour as Osmosis. @MAN_COMMON_OPTIONS@ @MAN_INPUT_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # DIAGNOSTICS **osmium derive-changes** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium derive-changes** doesn't keep a lot of data in memory. # EXAMPLES Find changes in Nepal extract in January 2016: osmium derive-changes nepal-20160101.osm.pbf nepal-20160201.osm.pbf -o nepal-jan.osc.bz2 # SEE ALSO * **osmium**(1), **osmium-file-formats**(5), **osmium-apply-changes**(1), **osmium-diff**(1) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-diff.md000066400000000000000000000067631315004223400173260ustar00rootroot00000000000000 # NAME osmium-diff - display differences between OSM files # SYNOPSIS **osmium diff** \[*OPTIONS*\] *OSM-FILE1* *OSM-FILE2* # DESCRIPTION Finds all differences between two OSM files and displays them. This command compares all attributes of all objects, so it will even find, say, differences in the user name or even the order of tags, differences that should not happen in normal OSM data unless there is also a different object version. Only differences between objects (node, ways, and relations) are found and displayed. Headers are ignored. Objects in both input files must be sorted in the same order. Several output formats are supported, see the **OUTPUT FORMATS** section. This command is intended for displaying the differences between files to humans. It can not be used to create an OSM change file (`.osc`), use **osmium-derive-changes** for that. # OUTPUT FORMATS The following output formats are supported and can be set with the **--output-format** or **-f** options. Default is the compact format. compact : A very compact format. For all objects a line is printed with the type of object ('n', 'w', or 'r'), the object ID and then the version number. If objects appear in both files and are identical they are preceded by a space (' ') character, if they are in both files, but different, they are preceded by an asterisk ('*'). Otherwise they get a minus ('-') or plus ('+') character to show that they are only in the first or second file, respectively. opl : The usual OPL format with all lines preceded by space (' '), minus ('-'), or plus ('+') characters depending on whether the object is in both, the first, or the second file. debug : The usual debug format with all lines preceded by space (' '), minus ('-'), or plus ('+') characters depending on whether the object is in both, the first, or the second file. Color support can be enabled ('debug,color'). None of the output formats print the headers of the input files. # OPTIONS -c, --suppress-common : Do not output objects that are the same in both files. -f, --output-format=FORMAT : See the **OUTPUT FORMATS** section. -o, --output=FILE : Name of the output file. Default is '-' (STDOUT). -O, --overwrite : Allow an existing output file to be overwritten. Normally **osmium** will refuse to write over an existing file. -q, --quiet : No output. Just report when files differ through the return code. -s, --summary : Print count of objects that are only in the left or right files, or the same in both or different in both to STDERR. -t, --object-type=TYPE : Read only objects of given type (*node*, *way*, *relation*). By default all types are read. This option can be given multiple times. This affects the output as well as the return code of the command. @MAN_COMMON_OPTIONS@ @MAN_INPUT_OPTIONS@ # DIAGNOSTICS **osmium diff** exits with exit code 0 ~ if the files are the same, 1 ~ if the files are different, or 2 ~ if there was an error # MEMORY USAGE **osmium diff** doesn't keep a lot of data in memory. # EXAMPLES Show difference between Nepal files from January 2016 and Febrary 2016 in compact format: osmium diff nepal-20160101.osm.pbf nepal-20160201.osm.pbf Show in color debug format only those objects that are different: osmium diff nepal-20160101.osm.pbf nepal-20160201.osm.pbf -f debug,color -c # SEE ALSO * **osmium**(1), **osmium-file-formats**(5), **osmium-derive-changes**(1) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-export.md000066400000000000000000000251121315004223400177240ustar00rootroot00000000000000 # NAME osmium-export - export OSM data # SYNOPSIS **osmium export** \[*OPTIONS*\] *OSM-FILE* # DESCRIPTION The OSM data model with its nodes, ways, and relations is very different from the data model usually used for geodata with features having point, linestring, or polygon geometries (or their cousins, the multipoint, multilinestring, or multipolygon geometries). The **export** command transforms OSM data into a more usual GIS data model. Nodes will be translated into points and ways into linestrings or polygons (if they are closed ways). Multipolygon and boundary relations will be translated into multipolygons. This transformation is not loss-less, especially information in non-multipolygon, non-boundary relations is lost. All tags are preserved in this process. Note that most GIS formats (such as Shapefiles, etc.) do not support arbitrary tags. Transformation into other GIS formats will need extra steps mapping tags to a limited list of attributes. This is outside the scope of this command. The **osmium export** command has to keep an index of the node locations in memory or in a temporary file on disk while doing its work. There are several different ways it can do that which have different advantages and disadvantages. The default is good enough for most cases, but see the **osmium-index-types**(5) man page for details. This program will not work on full history files. # OPTIONS -c, --config=FILE : Read configuration from specified file. -e, --show-errors : Output any geometry errors on STDERR. This includes ways with a single node or areas that can't be assembled from multipolygon relations. This output is not suitable for automated use, there are other tools that can create very detailed errors reports that are better for that (see http://osmcode.org/osm-area-tools/). -E, --stop-on-error : Usually geometry errors (due to missing node locations or broken polygons) are ignored and the features are omitted from the output. If this option is set, any error will immediately stop the program. -i, --index-type=TYPE : Set the index type. For details see the **osmium-index-types**(5) man page. -I, --show-index-types : Shows a list of available index types. For details see the **osmium-index-types**(5) man page. -n, --keep-untagged : If this is set features without any tags will be in the exported data. By default these features will be omitted from the output. Tags are the OSM tags, not attributes (like id, version, uid, ...) without the tags removed by the **exclude_tags** or **include_tags** settings. -r, --omit-rs : Do not print the RS (0x1e, record separator) character when using the GeoJSON Text Sequence Format. Ignored for other formats. -u, --add-unique-id=TYPE : Add a unique ID to each feature. TYPE can be either *counter* in which case the first feature will get ID 1, the next ID 2 and so on. The type of object does not matter in this case. Or the TYPE is *type_id* in which case the ID is a string, the first character is the type of object ('n' for nodes, 'w' for linestrings created from ways, and 'a' for areas created from ways and/or relations, after that there is a unique ID based on the original OSM object ID(s). @MAN_COMMON_OPTIONS@ @MAN_INPUT_OPTIONS@ # OUTPUT OPTIONS -f, --output-format=FORMAT : The format of the output file. Can be used to set the output file format if it can't be autodetected from the output file name. See the OUTPUT FORMATS section for a list of formats. --fsync : Call fsync after writing the output file to force flushing buffers to disk. -o, --output=FILE : Name of the output file. Default is '-' (STDOUT). -O, --overwrite : Allow an existing output file to be overwritten. Normally **osmium** will refuse to write over an existing file. # CONFIG FILE The config file is in JSON format. The top-level is an object which contains the following optional names: * `attributes`: An object specifying which attributes of OSM objects to export. See the ATTRIBUTES section. * `linear_tags`: An array of expressions specifying tags that should be treated as linear. See the FILTER EXPRESSION and AREA HANDLING sections. * `area_tags`: An array of expressions specifying tags that should be treated as area tags. See the FILTER EXPRESSION and AREA HANDLING sections. * `exclude_tags`: A list of tag expressions. Tags matching these expressions are excluded from the output. See the FILTER EXPRESSION section. * `include_tags`: A list of tag expressions. Tags matching these expressions are included in the output. See the FILTER EXPRESSION section. The `exclude_tags` and `include_tags` options are mutually exclusive. If you want to just exclude some tags but leave most tags untouched, use the `exclude_tags` setting. If you only want a defined list of tags, use `include_tags`. When no config file is specified, the following settings are used: @EXPORT_DEFAULT_CONFIG@ # FILTER EXPRESSIONS A filter expression specifies a tag or tags that should be matched in the data. Some examples: amenity : Matches all objects with the key "amenity". highway=primary : Matches all objects with the key "highway" and value "primary". highway!=primary : Matches all objects with the key "highway" and a value other than "primary". type=multipolygon,boundary : Matches all objects with key "type" and value "multipolygon" or "boundary". name,name:de=Kastanienallee,Kastanienstrasse : Matches any object with a "name" or "name:de" tag with the value "Kastanienallee" or "Kastanienstrasse". addr:\* : Matches all objects with any key starting with "addr:" name=\*Paris\* : Matches all objects with a name that contains the word "Paris". If there is no equal sign ("=") in the expression only keys are matched and values can by anything. If there is an equal sign ("=") in the expression, the key is to the left and the value to the right. An exclamation sign ("!") before the equal sign means: A tag with that key, but not the value(s) to the right of the equal sign. A leading or trailing asterisk ("\*") can be used for substring or prefix matching, respectively. Commas (",") can be used to separate several keys or values. All filter expressions are case-sensitive. There is no way to escape the special characters such as "=", "\*" and ",". You can not mix comma-expressions and "\*"-expressions. # ATTRIBUTES All OSM objects (nodes, ways, and relations) have *attributes*, areas inherit their attributes from the ways and/or relations they were created from. The attributes known to `osmium export` are: * `type` ('node', 'way', or 'relation') * `id` (64 bit object ID) * `version` (version number) * `changeset` (changeset ID) * `timestamp` (time of object creation in seconds since Jan 1 1970) * `uid` (user ID) * `user` (user name) * `way_nodes` (ways only, array with node IDs) For areas, the type will be `way` or `relation` if the area was created from a closed way or a multipolygon or boundary relation, respectively. The `id` for areas is the id of the closed way or the multipolygon or boundary relation. By default the attributes will not be in the export, because they are not necessary for most uses of OSM data. If you are interested in some (or all) attributes, add an `attributes` object to the config file. Add a member for each attribute you are interested in, the value can be either `false` (do not output this attribute), `true` (output this attribute with the attribute name prefixed by the `@` sign) or any string, in which case the string will be used as the attribute name. Note that the `id` is not necessarily unique. Even the combination `type` and `id` is not unique, because a way may end up as LineString and as Polygon on the file. See the `--add-unique-id` option for a unique ID. # AREA HANDLING Multipolygon relations will be assembled into multipolygon geometries forming areas. Some closed ways will also form areas. Here are the more detailed rules: * Non-closed ways (last node not the same as the first node) are always linestrings, not areas. * Relations tagged `type=multipolygon` or `type=boundary` are always assembled into areas. If they are not valid, they are omitted from the output (unless --stop-on-error/-E is specified). (An error message will be produced if the --show-errors/-e option is specified). * For closed ways the tags are checked. If they have an `area` tag other than `area=no`, they are areas and a polygon is created. If they have an `area` tag other than `area=yes`, they are linestrings. So closed ways can be both, an area and a linestring! * The configuration options `area_tags` and `linear_tags` can be used to augment the area check. If any of the tags on a closed way matches any of the expressions in `area_tags`, a polygon is created. If any of the tags on a closed way matches any of the expressions in `linear_tags`, a linestring is created. Again: If both match, an area and a linestring is created. # OUTPUT FORMATS The following output formats are supported: * `geojson` (alias: `json`): GeoJSON (RFC7946). The output file will contain a single `FeatureCollection` object. This is the default format. * `geojsonseq` (alias: `jsonseq`): GeoJSON Text Sequence (RFC8142). Each line (beginning with a RS (0x1e, record separator) and ending in a linefeed character) contains one GeoJSON object. Used for streaming GeoJSON. * `text` (alias: `txt`): A simple text format with the geometry in WKT format followed by the comma-delimited tags. This is mainly intended for debugging at the moment. THE FORMAT MIGHT CHANGE WITHOUT NOTICE! # DIAGNOSTICS **osmium export** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium export** will usually keep all node locations and all objects needed for assembling the areas in memory. For larger data files, this can need several tens of GBytes of memory. See the **osmium-index-types**(5) man page for details. # EXAMPLES Export into GeoJSON format: osmium export data.osm.pbf -o data.geojson Use a config file and export into GeoJSON Text Sequence format: osmium export data.osm.pbf -o data.geojsonseq -c export-config.json # SEE ALSO * **osmium**(1), **osmium-file-formats**(5), **osmium-index-types**(5), **osmium-add-node-locations-to-ways**(1) * [Osmium website](http://osmcode.org/osmium-tool/) * [GeoJSON](http://geojson.org/) * [RFC7946](https://tools.ietf.org/html/rfc7946) * [RFC8142](https://tools.ietf.org/html/rfc8142) * [Line delimited JSON](https://en.wikipedia.org/wiki/JSON_Streaming#Line_delimited_JSON) osmium-tool-1.7.1/man/osmium-extract.md000066400000000000000000000331251315004223400200600ustar00rootroot00000000000000 # NAME osmium-extract - create geographical extracts from an OSM file # SYNOPSIS **osmium extract** --config *CONFIG-FILE* \[*OPTIONS*\] *OSM-FILE*\ **osmium extract** --bbox *LEFT*,*BOTTOM*,*RIGHT*,*TOP* \[*OPTIONS*\] *OSM-FILE*\ **osmium extract** --polygon *POLYGON-FILE* \[*OPTIONS*\] *OSM-FILE* # DESCRIPTION Create geographical extracts from an OSM data file or an OSM history file. The region (geographical extent) can be given as a bounding box or as a (multi)polygon. There are three ways of calling this command: * Specify a config file with the --config/-c option. It can define any number of regions you want to cut out. See the **CONFIG FILE** section for details. * Specify a bounding box to cut out with the --bbox/-b option. * Specify a (multi)polygon to cut out with the --polygon/-p option. The input file is assumed to be ordered in the usual order: nodes first, then ways, then relations. If the `--with-history` option is used, the command will work correctly for history files. This currently works for the **complete_ways** strategy only. The **simple** or **smart** strategies do not work with history files. A history extract will contain every version of all objects with at least one version in the region. Generating a history extract is somewhat slower than a normal data extract. Osmium will make sure that all nodes on the vertices of the boundary of the region will be in the extract, but nodes that happen to be directly on the boundary, but between those vertices, might end up in the extract or not. In almost all cases this will be good enough, but if you want to make really sure you got everything, use a small buffer around your region. By default no **bounds** will be set in the header of the output file. Use the --set-bounds option if you need this. Note that **osmium extract** will never clip any OSM objects, ie. it will not remove node references outside the region from ways or unused relation members from relations. This means you might get objects that are not reference-complete. It has the advantage that you can use **osmium merge** to merge several extracts without problems. # OPTIONS -b, --bbox=LEFT,BOTTOM,RIGHT,TOP : Set the bounding box to cut out. Can not be used with --polygon/-p, --config/-c, or --directory/-d. -c, --config=FILE : Set the name of the config file. Can not be used with the --bbox/-b or --polygon/-p option. If this is set, the --output/-o and --output-format/-f options are ignored, because they are set in the config file. -d, --directory=DIRECTORY : Output directory. Output file names in the config file are relative to this directory. Overwrites the setting of the same name in the config file. This option is ignored when the --bbox/-b or --polygon/-p options are used, set the output directory and name with the --output/-o option in that case. -H, --with-history : Specify that the input file is a history file. The output file(s) will also be history file(s). -p, --polygon=POLYGON_FILE : Set the polygon to cut out based on the contents of the file. The file has to be a GeoJSON, poly, or OSM file as described in the **(MULTI)POLYGON FILE FORMATS** section. It has to have the right suffix to be detected correctly. Can not be used with --bbox/-b, --config/-c, or --directory/-d. -s, --strategy=STRATEGY : Use the given strategy to extract the region. For possible values and details see the **STRATEGIES** section. Default is "complete_ways". -S, --option=OPTION=VALUE : Set a named option for the strategy. If needed you can specify this option multiple times to set several options. --set-bounds : Set the bounds field in the header. The bounds are set to the bbox or envelope of the polygon specified for the extract. Note that strategies other than "simple" can put nodes outside those bounds into the output file. @MAN_COMMON_OPTIONS@ @MAN_INPUT_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # CONFIG FILE The config file mainly specifies the file names and the regions of the extracts that should be created. The config file is in JSON format. The top-level is an object which contains at least an "extracts" array. It can also contain a "directory" entry which names the directory where all the output files will be created: { "extracts": [...], "directory": "/tmp/" } The extracts array specifies the extracts that should be created. Each item in the array is an object with at least a name "output" naming the output file and a region defined in a "bbox", "polygon" or "multipolygon" name. An optional "description" can be added, it will not be used by the program but can help with documenting the file contents. You can add an optional "output_format" if the format can not be detected from the "output" file name. Run "osmium help file-formats" to get a description of allowed formats. The optional "output_header" allows you to set additional OSM file header settings such as the "generator". "extracts": [ { "output": "hamburg.osm.pbf", "output_format": "pbf", "description": "optional description", "box": ... }, { "output": "berlin.osm.pbf", "description": "optional description", "polygon": ... }, { "output": "munich.osm.pbf", "output_header": { "generator": "MyExtractor/1.0" }, "description": "optional description", "multipolygon": ... } ] There are several formats for specifying the regions: **box**: A bounding box in one of two formats. The first is a simple array with four real numbers specifying the left, bottom, right, and top boundary (in that order): { "output": "munich.osm.pbf", "description": "Bounding box specified in array format", "bbox": [11.35, 48.05, 11.73, 48.25] } The second format uses an object instead of an array: { "output": "dresden.osm.pbf", "description": "Bounding box specified in object format", "bbox": { "left": 13.57, "right": 13.97, "top": 51.18, "bottom": 50.97 } } **polygon**: A polygon, either specified inline in the config file or read from an external file. See the **(MULTI)POLYGON FILE FORMATS** section for external files. If specified inline this is a nested array, the outer array defining the polygon, the next array the rings and the innermost arrays the coordinates. This format is the same as in GeoJSON files. In this example there is only one outer ring: "polygon": [[ [9.613465, 53.58071], [9.647599, 53.59655], [9.649288, 53.61059], [9.613465, 53.58071] ]] In each ring, the last set of coordinates should be the same as the first set, closing the ring. **multipolygon**: A multipolygon, either specified inline in the config file or read from an external file. See the **(MULTI)POLYGON FILE FORMATS** section for external files. If specified inline this is a nested array, the outer array defining the multipolygon, the next array the polygons, the next the rings and the innermost arrays the coordinates. This format is the same as in GeoJSON files. In this example there is one outer and one inner ring: "multipolygon": [[[ [6.847, 50.987], [6.910, 51.007], [7.037, 50.953], [6.967, 50.880], [6.842, 50.925], [6.847, 50.987] ],[ [6.967, 50.954], [6.969, 50.920], [6.932, 50.928], [6.934, 50.950], [6.967, 50.954] ]]] In each ring, the last set of coordinates should be the same as the first set, closing the ring. Osmium must check each and every node in the input data and find out in which bounding boxes or (multi)polygons this node is. This is very cheap for bounding boxes, but more expensive for (multi)polygons. And it becomes more expensive the more vertices the (multi)polyon has. Use bounding boxes or simplified polygons where possible. Note that bounding boxes or (multi)polygons are not allowed to span the -180/180 degree line. If you need this, cut out the regions on each side and use **osmium merge** to join the resulting files. # (MULTI)POLYGON FILE FORMATS External files describing a (multi)polygon are specified in the config file using the "file_name" and "file_type" properties on the "polygon" or "multipolygon" object: "polygon": { "file_name": "berlin.geojson", "file_type": "geojson" } If file names don't start with a slash (/), they are interpreted relative to the directory where the config file is. If the "file_type" is missing, Osmium will try to autodetect it from the suffix of the "file_name". The following file types are supported: geojson : GeoJSON file containing exactly one polygon or multipolygon. Everything except the actual geometry is ignored. poly : A poly file as described in https://wiki.openstreetmap.org/wiki/Osmosis/Polygon_Filter_File_Format . This wiki page also mentions several sources for such poly files. osm : An OSM file containing one or more multipolygon or boundary relation together with all the nodes and ways needed. Any OSM file format (XML, PBF, ...) supported by Osmium can be used here, but the correct suffix must be used, so the file format is detected correctly. Files for this can easily be obtained by searching for the area on OSM and then downloading the full relation using a URL like http://www.openstreetmap.org/api/0.6/relation/RELATION-ID/full . Or you can use **osmium getid -r** to get a specific relation from an OSM file. Note that both these approaches can get you very detailed boundaries which can take quite a while to cut out. Consider simplifying the boundary before use. If there are several (multi)polygons in a poly file or OSM file, they will be merged. The (multi)polygons must not overlap, otherwise the result is undefined. # STRATEGIES **osmium extract** can use different strategies for creating the extracts. Depending on the strategy different objects will end up in the extracts. The strategies differ in how much memory they need and how often they need to read the input file. The choice of strategy depends on how you want to use the generated extracts and how much memory and time you have. The default strategy is **complete_ways**. Strategy **simple** : Runs in a single pass. The extract will contain all nodes inside the region and all ways referencing those nodes as well as all relations referencing any nodes or ways already included. Ways crossing the region boundary will not be reference-complete. Relations will not be reference-complete. This strategy is fast, because it reads the input only once, but the result is not enough for most use cases. It is the only strategy that will work when reading from a socket or pipe. This strategy will not work for history files. Strategy **complete_ways** : Runs in two passes. The extract will contain all nodes inside the region and all ways referencing those nodes as well as all nodes referenced by those ways. The extract will also contain all relations referenced by nodes inside the region or ways already included and, recursively, their parent relations. The ways are reference-complete, but the relations are not. Strategy **smart** : Runs in three passes. The extract will contain all nodes inside the region and all ways referencing those nodes as well as all nodes referenced by those ways. The extract will also contain all relations referenced by nodes inside the region or ways already included and, recursively, their parent relations. The extract will also contain all nodes and ways (and the nodes they reference) referenced by relations tagged "type=multipolygon" directly referencing any nodes in the region or ways referencing nodes in the region. The ways are reference-complete, and all multipolygon relations referencing nodes in the regions or ways that have nodes in the region are reference-complete. Other relations are not reference-complete. For the **smart** strategy you can change the types of relations that should be reference-complete. Instead of just relations tagged "type=multipolygon", you can either get all relations (use "-S types=any") or give a list of types to the -S option: "-S types=multipolygon,route". Note that especially boundary relations can be huge, so if you include them, be aware your result might be huge. # DIAGNOSTICS **osmium extract** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments, config file or polygon files. # MEMORY USAGE Memory usage of **osmium extract** depends on the number of extracts and on the strategy used. For the *simple* strategy it will at least be the number of extracts times the highest node ID used divided by 8. For the *complete_ways* twice that and for the *smart* strategy a bit more. # EXAMPLES See the example config files in the *extract-example-config* directory. To try it: osmium extract -v -c extract-example-config/extracts.json \ germany-latest.osm.pbf Extract the city of Karlsruhe using a boundary polygon: osmium -p karlsruhe-boundary.osm.bz2 germany-latest.osm.pbf \ -o karlsruhe.osm.pbf Extract the city of Munich using a bounding box: osmium -b 11.35,48.05,11.73,48.25 germany-latest.osm.pbf \ -o munich.osm.pbf # SEE ALSO * **osmium**(1), **osmium-file-formats**(5), **osmium-getid**(1), **osmium-merge**(1) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-file-formats.md000066400000000000000000000100501315004223400207660ustar00rootroot00000000000000 # NAME osmium-file-formats - OSM file formats known to Osmium # FILE TYPES OSM uses three types of files for its main data: **Data files** : These are the most common files containing the OSM data at a specific point in time. This can either be a planet file containing *all* OSM data or some kind of extract. At most one version of every object (node, way, or relation) is contained in this file. Deleted objects are *not* in this file. The usual suffix used is `.osm`. **History files** : These files contain not only the current version of an object, but their history, too. So for any object (node, way, or relation) there can be zero or more versions in this file. Deleted objects can also be in this file. The usual suffix used is `.osm` or `.osh`. Because sometimes the same suffix is used as for normal data files (`.osm`) and because there is no clear indicator in the header, it is not always clear what type of file you have in front of you. **Change files** : Sometimes called *diff files* or *replication diffs* these files contain the changes between one state of the OSM database and another state. Change files can contains several versions of an object. The usual suffix used is `.osc`. All these files have in common that they contain OSM objects (nodes, ways, and relations). History files and change files can contain several versions of the same object and also deleted objects, data files can't. Where possible, Osmium commands can handle all file types. For some commands only some file types make sense. # FORMATS The **osmium** command line tool supports all major OSM file formats plus some more. These are: * The classical XML format in the variants *.osm* (for data files), *.osh* (for data files with history) and *.osc* (for change files). * The PBF binary format (usually with suffix *.osm.pbf* or just *.pbf*). * The OPL format (usually with suffix *.osm.opl* or just *.opl*). * The O5M/O5C format (usually with suffix *.o5m* or *.o5c*) (reading only). * The "debug" format (usually with suffix *.osm.debug*) (writing only). In addition files in all formats except PBF can be compressed using *gzip* or *bzip2*. (Add *.gz* or *.bz2* suffixes, respectively.) # AUTODETECTION Which format a file has is usually autodetected from the file name suffix. If this doesn't work, either because you are reading from STDIN or writing to STDOUT, or because you have an unusual file name, you have to set the format manually. You can also set the format manually if you want to specify special format options. Most **osmium** commands support the **--input-format** (**--F**) and **--output-format** (**-f**) options to set the format. They take a comma-separated list of arguments, the first is the format, further arguments set additional options. # SPECIAL FORMAT OPTIONS The following options can be added when writing OSM files: `xml_change_format`=`true`/`false` : Enable/disable XML change format. Same as *.osc*. `force_visible_flag`=`true`/`false` (*default: false*) : Force writing of visible flag, even for normal OSM XML files. `pbf_dense_nodes`=`true`/`false` (*default: true*) : Enable/disable DenseNodes format for PBF files. `pbf_compression`=`true`/`false` (*default: true*) : Enable/disable compression in PBF files. Disabling this will make writing files a bit faster, but the resulting files are 2 to 3 times bigger. `add_metadata`=`true`/`false` (*default: true*) : Enable/disable writing of object metadata such as changeset id, username, etc. Disabling this will make files a bit smaller. # EXAMPLES Here are some examples: `pbf` : PBF format. `pbf,add_metadata=false` : PBF format, dont' write metadata `osm.bz2` : XML format, compressed with bzip2. `osc.gz` : OSM change file, compressed with gzip. `osm.gz,xml_change_format=true` : OSM change file, compressed with gzip. `osh.opl` : OSM history file in OPL format. # SEE ALSO * **osmium**(1) * [Osmium website](http://osmcode.org/osmium-tool/) * [OSM File Formats Manual](http://osmcode.org/file-formats-manual/) osmium-tool-1.7.1/man/osmium-fileinfo.md000066400000000000000000000077651315004223400202140ustar00rootroot00000000000000 # NAME osmium-fileinfo - show information about an OSM file # SYNOPSIS **osmium fileinfo** \[*OPTIONS*\] *OSM-FILE* # DESCRIPTION Shows various information about OSM files such as the file type, bounding boxes in the header, etc. This command will usually only read the file header. Use the **--extended** option to show more information. Normally this command will output the data in human readable form. If the **-j**, **--json** option is used, the output will be in JSON format instead. If the **-g**, **--get** option is used, only the value of the named variable will be printed. The output is split into three sections: File : This section shows the information available without opening the file itself. It contains the file name, the format deduced from the file name, the compression used and the size of the file in bytes. Header : This section shows the information available from the header of the file (if available, OPL files have no header). Any available bounding boxes are shown as well as header options such as the generator and file format version. Data : This section shows the information available from reading the whole file. It is only shown if the **--extended** option was used. It shows the actual bounding box calculated from the nodes in the file, the first and last timestamp of all objects in the file, a CRC32 checksum of the data in the file, the number of changesets, nodes, ways, and relations found in the file, whether the objects in the file were ordered by type (nodes, then ways, then relations) and id, and whether there were multiple versions of the same object in the file (history files and change files can have that). See the **osmium-sort**(1) man page for details of the expected ordering. This commands reads its input file only once, ie. it can read from STDIN. # OPTIONS -e, --extended : Read the complete file and show additional information. The default is to read only the header of the file. -g, --get=VARIABLE : Get value of VARIABLE. Can not be used together with --json. -G, --show-variables : Show a list of all variable names. -j, --json : Output in JSON format. Can not be used together with --get. @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_OPTIONS@ @MAN_INPUT_OPTIONS@ # VARIABLES The following variables are available: file.name - STRING file.format - STRING: XML|PBF file.compression - STRING: none|bzip2|gzip file.size - INTEGER (always 0 when reading from STDIN) header.with_history - BOOL (yes|no) header.option.generator - STRING header.option.version - STRING header.option.pbf_dense_nodes - BOOL (yes|no) header.option.osmosis_replication_timestamp - STRING with TIMESTAMP header.option.osmosis_replication_sequence_number - INTEGER header.option.osmosis_replication_base_url - STRING data.bbox - BOX (in JSON as nested ARRAY with coordinates) data.timestamp.first - STRING with TIMESTAMP data.timestamp.last - STRING wih TIMESTAMP data.objects_ordered - BOOL (yes|no) data.multiple_versions - STRING (yes|no|unknown) (in JSON as BOOL and missing if "unknown") data.crc32 - STRING with 8 hex digits data.count.nodes - INTEGER data.count.ways - INTEGER data.count.relations - INTEGER data.count.changesets - INTEGER data.maxid.nodes - INTEGER data.maxid.ways - INTEGER data.maxid.relations - INTEGER data.maxid.changesets - INTEGER All timestamps are in the usual OSM ISO format `yy-mm-ddThh::mm::ssZ`. Boxes are in the format `(xmin, ymin, xmax, ymax)`. # DIAGNOSTICS **osmium fileinfo** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium fileinfo** does all its work on the fly and doesn't keep much data in main memory. # SEE ALSO * **osmium**(1), **osmium-file-formats**(5), **osmium-sort**(1) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-getid.md000066400000000000000000000112601315004223400174760ustar00rootroot00000000000000 # NAME osmium-getid - get objects from OSM file by ID # SYNOPSIS **osmium getid** \[*OPTIONS*\] *OSM-FILE* *ID*...\ **osmium getid** \[*OPTIONS*\] *OSM-FILE* -i *ID-FILE*\ **osmium getid** \[*OPTIONS*\] *OSM-FILE* -I *ID-OSM-FILE* # DESCRIPTION Get objects with the given IDs from the input and write them to the output. IDs can be given on the command line (first case in synopsis), or read from text files with one ID per line (second case in synopsis), or read from OSM files (third cases in synopsis). A mixture of these cases is also allowed. All objects with these IDs will be read from *OSM-FILE* and written to the output. If the option **-r**, **--add-referenced** is used all objects referenced from those objects will also be added to the output. Objects will be written out in the order they are found in the *OSM-FILE*. If the option **-r**, **--add-referenced** is *not* used, the input file is read only once, if it is used, the input file will possibly be read up to three times. On the command line or in the ID file, the IDs have the form: *TYPE-LETTER* *NUMBER*. The type letter is 'n' for nodes, 'w' for ways, and 'r' for relations. If there is no type letter, 'n' for nodes is assumed (or whatever the **--default-type** option says). So "n13 w22 17 r21" will match the nodes 13 and 17, the way 22 and the relation 21. The order in which the IDs appear does not matter. Identical IDs can appear multiple times on the command file or in the ID file(s). On the command line, the list of IDs can be in separate arguments or in a single argument separated by spaces, tabs, commas (,), semicolons (;), forward slashes (/) or pipe characters (|). In an ID file (option **-i**/**--id-file**) each line must start with an ID in the format described above. Leading space characters in the line are ignored. Lines can optionally contain a space character or a hash sign ('#') after the ID. Any characters after that are ignored. (This also allows files in OPL format to be read.) Empty lines are ignored. Note that all objects will be taken from the *OSM-FILE*, the *ID-OSM-FILE* is only used to detect which objects to get. This might matter if there are different object versions in the different files. The *OSM-FILE* can not be a history file unless the **-H**, **--with-history** option is used. Then all versions of the objects will be copied to the output. If referenced objects are missing from the input file, the type and IDs of those objects is written out to STDERR at the end of the program unless the **-H**, **--with-history** option was given. This command will not work with negative IDs. # OPTIONS --default-type=TYPE : Use TYPE ('node', 'way', or 'relation') for IDs without a type prefix (default: 'node'). It is also allowed to just use the first character of the type here. --history : Deprecated. Use --with-history instead. -H, --with-history : Make this program work on history files. This is only needed when using the **-r** option. -i, --id-file[=FILE] : Read IDs from text file instead of from the command line. Use the special name "-" to read from *STDIN*. Each line of the file must start with an ID in the format described above. Lines can optionally contain a space character or a hash sign ('#') after the ID. This character and all following characters are ignored. (This allows files in OPL format to be read.) Empty lines are also ignored. This option can be used multiple times. -I, --id-osm-file=OSMFILE : Like **-i** but get the IDs from an OSM file. This option can be used multiple times. -r, --add-referenced : Recursively find all objects referenced by the objects of the given IDs and include them in the output. This only works correctly on non-history files unless the `-H` option is also used. --verbose-ids : Also print all requested and missing IDs. This is usually disabled, because the lists can get quite long. (This option implies `--verbose`.) @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_OPTIONS@ @MAN_INPUT_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # DIAGNOSTICS **osmium getid** exits with exit code 0 ~ if all IDs were found 1 ~ if there was an error processing the data or not all IDs were found, (this is only detected if the **-H**, **--with-history** option was not used), 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium getid** does all its work on the fly and only keeps a table of all IDs it needs in main memory. # EXAMPLES Output nodes 17 and 1234, way 42, and relation 111 to STDOUT in OPL format: osmium getid -f opl planet.osm.pbf n1234 w42 n17 r111 # SEE ALSO * **osmium**(1), **osmium-file-formats**(5) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-index-types.md000066400000000000000000000043411315004223400206550ustar00rootroot00000000000000 # NAME osmium-index-types - Index types used to store node locations # DESCRIPTION The **osmium add-locations-to-ways** and **osmium export** commands have to keep an index of the node locations in memory or in a temporary file on disk while doing their work. There are several different ways this can be done which have different advantages and disadvantages. Use the **--show-index-types**, **-I** option on these commands to show all available index types. It depends on your operating system which index types are available. Use the **--index-type**, **-i** option on these commands to set the index type to be used. The default index type is `flex_mem` which will keep all data in memory and works for small extracts as well as the whole planet file. It is the right choice for almost all use cases if you have enough memory to keep the whole index in memory. For the **osmium export** command, the special type `none` is used when reading from files with the node locations on the ways. (See **osmium-add-node-locations-to-ways**(1) for how to get a file like this.) You can use one of the file-based indexes for the node location store to minimize memory use, but performance will suffer. In this case use `sparse_file_array` if you have a small or medium sized extract and `dense_file_array` if you are working with a full planet or a really large extract. # MEMORY USE It depends on the index type used how much memory is needed: * For `sparse_*_array` types 16 bytes per node in the input file are used. * For `dense_*_array` types 8 bytes times the largest node ID in the input file are used. The `*_mem_*` types use potentially up to twice this amount. The `*mem*` and `*mmap*` types store the data in memory, the `*file*` types in a file on disk. The `flex_mem` type automatically switches between something similar to `sparse_mmap_array` for smaller extracts and `dense_mmap_array` for larger extracts or the whole planet file. If you specify the **--verbose**, **-v** option, Osmium will display how much memory was used for the index. # SEE ALSO * **osmium**(1), **osmium-add-locations-to-ways**(1), **osmium-export**(1) * [Osmium website](http://osmcode.org/osmium-tool/) * [Index types](http://osmcode.org/osmium-concepts/#indexes) osmium-tool-1.7.1/man/osmium-merge-changes.md000066400000000000000000000032751315004223400211160ustar00rootroot00000000000000 # NAME osmium-merge-changes - merge several OSM change files into one # SYNOPSIS **osmium merge-changes** \[*OPTIONS*\] *OSM-CHANGE-FILE*... # DESCRIPTION Merges the content of all change files given on the command line into one large change file. Objects are sorted by type, ID, version, and timestamp so it doesn't matter in what order the change files are given or in what order they contain the data. This commands reads its input file(s) only once and writes its output file in one go so it can be streamed, ie. it can read from STDIN and write to STDOUT. # OPTIONS -s, --simplify : Only write the last version of any object to the output. For an object created in one of the change files and removed in a later one, the deleted version of the object will still appear because it is the latest version. @MAN_COMMON_OPTIONS@ @MAN_INPUT_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # DIAGNOSTICS **osmium merge-changes** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium merge-changes** keeps the contents of all the change files in main memory. This will take roughly 10 times as much memory as the files take on disk in *.osm.bz2* format. # EXAMPLES Merge all changes in *changes* directory into *all.osc.gz*: osmium merge-changes -o all.osc.gz changes/*.gz Because `osmium merge-changes` sorts its input, you can also use it to sort just a single change file: osmium merge-changes unsorted.osc.gz -o sorted.osc.gz # SEE ALSO * **osmium**(1), **osmium-file-formats**(5), **osmium-merge**(1) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-merge.md000066400000000000000000000037301315004223400175040ustar00rootroot00000000000000 # NAME osmium-merge - merge several sorted OSM files into one # SYNOPSIS **osmium merge** \[*OPTIONS*\] *OSM-FILE*... # DESCRIPTION Merges the content of all OSM files given on the command line into one large OSM file. Objects in all files must be sorted by type, ID, and version. The results will also be sorted in the same way. Objects that appear in multiple input files will only be in the output once. If there is only a single input file, its contents will be copied to the output. If there are different versions of the same object in the input files, all versions will appear in the output. So this command will work fine with history files as input creating a new history file. Do not use this command to merge non-history files with data from different points in time. It will not work correctly. If you have objects with the same type, id, and version but different other data, the result of this command is undefined. This situation can never happen in correct OSM files, but sometimes buggy programs can generate data like this. Osmium doesn't make any promises on what the result of the command is if the input data is not correct. This commands reads its input file(s) only once and writes its output file in one go so it can be streamed, ie. it can read from STDIN and write to STDOUT. @MAN_COMMON_OPTIONS@ @MAN_INPUT_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # DIAGNOSTICS **osmium merge** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium merge** doesn't keep a lot of data in memory, but if you are merging many files, the buffers might take a noticeable amount of memory. # EXAMPLES Merge several extracts into one: osmium merge washington.pbf oregon.pbf california.pbf -o westcoast.pbf # SEE ALSO * **osmium**(1), **osmium-file-formats**(5), **osmium-merge-changes**(1) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-renumber.md000066400000000000000000000074221315004223400202260ustar00rootroot00000000000000 # NAME osmium-renumber - renumber object IDs # SYNOPSIS **osmium renumber** \[*OPTIONS*\] *OSM-DATA-FILE* # DESCRIPTION The objects (nodes, ways, and relations) in an OSM file often have very large IDs. This can make some kinds of postprocessing difficult. This command will renumber all objects using IDs starting at 1. Referential integrity will be kept. All objects which appear in the source file will be in the same order in the output file. IDs of objects which are not in the file but referenced from ways or relations are not guaranteed to be in the correct order. This command expects the input file to be ordered in the usual way: First nodes in order of ID, then ways in order of ID, then relations in order of ID. Negative IDs are allowed, they must be ordered before the positive IDs. See the **osmium-sort**(1) man page for details of the ordering. The input file will be read twice, so it will not work with STDIN. If you are not renumbering relations (ie. if the option **--object-type/-t** is used with nodes and/or ways but not relations) the input file will only be read once, so in that case it will work with STDIN. To renumber the IDs in several files, call **osmium renumber** for each file and specify the `-i` or `--index-directory` option each time. See the **INDEX FILES** section for more details. You must never upload the data generated by this command to OSM! This would really confuse the OSM database because it knows the objects under different IDs. # OPTIONS -i, --index-directory=DIR : Directory where the index files for mapping between old and news IDs are read from and written to, respectively. Use this if you want to map IDs in several OSM files. Without this option, the indexes are not read from or written to disk. The directory must exist. Use '.' for the current directory. The files written will be named `nodes.idx`, `ways.idx`, and `relations.idx`. See also the **INDEX FILES** section below. -t, --object-type=TYPE : Renumber only objects of given type (*node*, *way*, or *relation*). By default all objects of all types are renumbered. This option can be given multiple times. @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_OPTIONS@ @MAN_INPUT_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # INDEX FILES When the `-i` or `--index-directory` option is used, index files named `nodes.idx`, `ways.idx`, and `relations.idx` are read from and written to the given directory. This can be used to force consistent mapping over several invocations of `osmium renumber`, for instance when you want to remap an OSM data file and a corresponding OSM change file. The index files are in binary format, but you can use the following command line to convert them into something readable: od -An -td8 -w8 TYPE.idx | cat -n # DIAGNOSTICS **osmium renumber** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium renumber** needs quite a bit of main memory to keep the mapping between old and new IDs. It is intended for small to medium sized extracts. You will need more than 32 GB RAM to run this on a full planet. Memory use is at least 8 bytes per node, way, and relation ID in the input file. # EXAMPLES Renumber a PBF file and output to a compressed XML file: osmium renumber -o ch.osm.bz2 germany.osm.pbf Renumbering Germany currently (spring 2016) takes less than three minutes and needs about 3 GB RAM. Renumber an OSM file storing the indexes on disk: osmium renumber -i. -o renumbered.osm data.osm then rewrite a change file, too: osmium renumber -i. -o renumbered.osc changes.osc # SEE ALSO * **osmium**(1), **osmium-file-formats**(5), **osmium-sort**(1) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-show.md000066400000000000000000000041121315004223400173600ustar00rootroot00000000000000 # NAME osmium-show - show OSM file # SYNOPSIS **osmium show** \[*OPTIONS*\] *OSM-FILE* # DESCRIPTION Show the contents of the *OSM-FILE* on STDOUT, usually in a pager. The output format can be set using the **-f**, **output-format** option, its shortcuts **-d** (debug format with colors), **-o** (OPL), or **-x** (XML), or the `OSMIUM_SHOW_FORMAT` environment variable. The pager can be set with the `OSMIUM_PAGER` or the `PAGER` environment variable. If neither is set, the default `less` is used unless the option `--no-pager` is used. If the pager variables are set to an empty value or to `cat`, no pager is used. On Windows there is no pager support at all. This commands reads its input file only once, ie. it can read from STDIN. # OPTIONS -f, --output-format=FORMAT : The format of the output file. Can be used to set the output file format if it can't be autodetected from the output file name. **See osmium-file-formats**(5) or the libosmium manual for details. --no-pager : Disable pager. -d, --format-debug : Same as `-f debug,color=true`. -o, --format-opl : Same as `-f opl`. -x, --format-xml : Same as `-f xml`. -t, --object-type=TYPE : Read only objects of given type (*node*, *way*, *relation*, *changeset*). By default all types are read. This option can be given multiple times. # COMMON OPTIONS -h, --help : Show usage help. @MAN_INPUT_OPTIONS@ # DIAGNOSTICS **osmium show** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium show** does all its work on the fly and doesn't keep much data in main memory. # EXAMPLES Show an OSM file using the default pager and default format: osmium show norway.osm.pbf Use `more` as a pager and only show relations: OSMIUM_PAGER=more osmium show -t r norway.osm.pbf Show using XML format: osmium show -x norway.osm.pbf # SEE ALSO * **osmium**(1), **osmium-cat**(1), **osmium-file-formats**(5) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-sort.md000066400000000000000000000030251315004223400173710ustar00rootroot00000000000000 # NAME osmium-sort - sort OSM files # SYNOPSIS **osmium sort** \[*OPTIONS*\] *OSM-FILE*... # DESCRIPTION Merges the content of all input files given on the command line and sort the result. Objects are sorted by type, ID, and version. IDs are sorted negative IDs first, the positive IDs, both ordered by their absolute values. So the sort order for types and IDs is: node -1, node -2, ..., node 1, node 2, ..., way -1, way -2, ..., way 1, way 2, ..., relation -1, relation -2, ..., relation 1, relation 2, ... If there are several objects of the same type and with the same ID they are ordered by ascending version. This command works with normal OSM data files, history files, and change files. This commands reads its input file(s) only once and writes its output file in one go so it can be streamed, ie. it can read from STDIN and write to STDOUT. @MAN_COMMON_OPTIONS@ @MAN_INPUT_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # DIAGNOSTICS **osmium sort** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium sort** keeps the contents of all the input files in main memory. This will take roughly 10 times as much memory as the files take on disk in *.osm.bz2* or *osm.pbf* format. # EXAMPLES Sort *in.osm.bz2* and write out to *sorted.osm.pbf*: osmium sort -o sorted.osm.pbf in.osm.bz2 # SEE ALSO * **osmium**(1), **osmium-file-formats**(5) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-tags-filter.md000066400000000000000000000114551315004223400206310ustar00rootroot00000000000000 # NAME osmium-tags-filter - filter objects matching specified keys/tags # SYNOPSIS **osmium tags-filter** \[*OPTIONS*\] *OSM-FILE* *FILTER-EXPRESSION*...\ **osmium tags-filter** \[*OPTIONS*\] --expressions=*FILE* *OSM-FILE* # DESCRIPTION Get objects matching the specified expressions from the input and write them to the output. Expressions can either be specified on the command line or in an expressions file. See the **FILTER EXPRESSIONS** section for a description of the filter expression format. All objects matching the expressions will be read from *OSM-FILE* and written to the output. All objects referenced from those objects will also be added to the output unless the option **-R**, **--omit-referenced** is used. This applies to nodes referenced in ways and members referenced in relations. If the option **-R**, **--omit-referenced** is used, the input file is read only once, otherwise the input file will possibly be read up to three times. Objects will be written out in the order they are found in the *OSM-FILE*. The command will only work correctly on history files if the **-R**/**--omit-referenced** option is used. # OPTIONS -e FILE, --expressions=FILE : Read expressions from the specified file, one per line. Empty lines are ignored. Everything after the comment character (#) is also ignored. The the **FILTER EXPRESSIONS** section for further details. -i, --invert-match : Invert the sense of matching. Exclude all objects with matching tags. -R, --omit-referenced : Omit the nodes referenced from matching ways and members referenced from matching relations. @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_OPTIONS@ @MAN_INPUT_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # FILTER EXPRESSIONS A filter expression specifies a tag or tags that should be found in the data and the type of object (node, way, or relation) that should be matched. The object type(s) comes first, then a slash (/) and then the rest of the expression. Object types are specified as 'n' (for nodes), 'w' (for ways), and 'r' (for relations). Any combination of them can be used. If the object type is not specified, the expression matches all object types. Some examples: n/amenity : Matches all nodes with the key "amenity". nw/highway : Matches all nodes or ways with the key "highway". /note : Matches objects of any type with the key "note". note : Matches objects of any type with the key "note". w/highway=primary : Matches all ways with the key "highway" and value "primary". w/highway!=primary : Matches all ways with the key "highway" and a value other than "primary". r/type=multipolygon,boundary : Matches all relations with key "type" and value "multipolygon" or "boundary". w/name,name:de=Kastanienallee,Kastanienstrasse : Matches any way with a "name" or "name:de" tag with the value "Kastanienallee" or "Kastanienstrasse". n/addr:\* : Matches all nodes with any key starting with "addr:" n/name=\*Paris\* : Matches all nodes with a name that contains the word "Paris". If there is no equal sign ("=") in the expression only keys are matched and values can by anything. If there is an equal sign ("=") in the expression, the key is to the left and the value to the right. An exclamation sign ("!") before the equal sign means: A tag with that key, but not the value(s) to the right of the equal sign. A leading or trailing asterisk ("\*") can be used for substring or prefix matching, respectively. Commas (",") can be used to separate several keys or values. All filter expressions are case-sensitive. There is no way to escape the special characters such as "=", "\*" and ",". You can not mix comma-expressions and "\*"-expressions. The filter expressions specified in a file and/or on the command line are matched in the order they are given. To achieve best performance, put expressions expected to match more often first. # DIAGNOSTICS **osmium tags-filter** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium tags-filter** does all its work on the fly and only keeps tables of object IDs it needs in main memory. If the **-R**/**--omit-referenced** option is used, no IDs are kept in memory. # EXAMPLES Get all amenity nodes from the Berlin PBF file: osmium tags-filter -o amenties.osm.pbf berlin.osm.pbf n/amenity Get all objects (nodes, ways, or relations) with a `note` tag: osmium tags-filter -R -o notes.osm.pbf berlin.osm.pbf note Get all nodes and ways with a `highway` tag and all relations tagged with `type=restriction` plus all referenced objects: osmium tags-filter -o filtered.osm.pbf planet.osm.pbf \ nw/highway r/type=restriction # SEE ALSO * **osmium**(1), **osmium-file-formats**(5) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium-time-filter.md000066400000000000000000000034301315004223400206230ustar00rootroot00000000000000 # NAME osmium-time-filter - filter OSM data by time from a history file # SYNOPSIS **osmium time-filter** \[*OPTIONS*\] *OSM-HISTORY-FILE* \[*TIME*\]\ **osmium time-filter** \[*OPTIONS*\] *OSM-HISTORY-FILE* *FROM-TIME* *TO-TIME* # DESCRIPTION Copy all objects that were valid at the given *TIME* or in the time period between *FROM-TIME* (inclusive) and *TO-TIME* (not inclusive) from the input file into the output file. If no time is given, the current time is used. Usually the *INPUT-FILE* will be an OSM data file with history. If both *FROM-TIME* and *TO-TIME* are given, the result will also have history data, it will also include deleted versions of objects. If only a single point in time was given, the result will be a normal OSM file without history containing no deleted objects. The format for the timestamps is "yyyy-mm-ddThh:mm::ssZ". This commands reads its input file only once and writes its output file in one go so it can be streamed, ie. it can read from STDIN and write to STDOUT. @MAN_COMMON_OPTIONS@ @MAN_INPUT_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # DIAGNOSTICS **osmium time-filter** exits with exit code 0 ~ if everything went alright, 1 ~ if there was an error processing the data, or 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium time-filter** does all its work on the fly and doesn't keep much data in main memory. # EXAMPLES Extract current planet file from history planet: osmium time-filter -o planet.osm.pbf history-planet.osh.pbf Extract planet data how it appeared on January 1 2008 from history planet: osmium time-filter -o planet-20080101.osm.pbf history-planet.osh.pbf 2008-01-01T00:00:00Z # SEE ALSO * **osmium**(1), **osmium-file-formats**(5) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/osmium.md000066400000000000000000000055431315004223400164130ustar00rootroot00000000000000 # NAME osmium - multipurpose tool for working with OpenStreetMap data # SYNOPSIS **osmium** *COMMAND* \[*ARG*...\]\ **osmium** --version # DESCRIPTION Multipurpose tool for working with OpenStreetMap data. Run **osmium help** *COMMAND* to get more information about a command. # OPTIONS -h, --help : Show usage and list of commands. --version : Show program version. # COMMANDS add-locations-to-ways : add node locations to ways in OSM file apply-changes : apply OSM change file(s) to OSM data file cat : concatenate OSM files and convert to different formats changeset-filter : filter changesets from OSM changeset files check-refs : check referential integrity of OSM file derive-changes : create OSM change file from two OSM files diff : display differences between OSM files export : export OSM data extract : create geographical extracts from an OSM file fileinfo : show information about an OSM file getid : get objects from OSM file by ID help : show help about commands merge : merge several OSM files into one merge-changes : merge several OSM change files into one renumber : renumber object IDs show : show OSM file sort : sort OSM files tags-filter : filter OSM data based on tags time-filter : filter OSM data by time from a history file # COMMON OPTIONS Most commands support the following options: -h, --help : Show short usage information. -v, --verbose : Set verbose mode. The program will output information about what it is doing to STDERR. # MEMORY USAGE Osmium commands try to do their work as memory efficient as possible. But some osmium commands still need to load quite a bit of data into main memory. In some cases this means that only smaller datasets can be handled. Look into the man pages for the individual commands to learn more about their memory use. If you use the **-v**, **--verbose** option on most commands they will print out their peak memory usage at the end. This is the actual amount of memory used including the program code itself, any needed libraries and the data. (Printing of memory usage is currently only available on Linux systems.) If an osmium command exits with an "Out of memory" error, try running it with **--verbose** on smaller datasets to get an idea how much memory it needs. # SEE ALSO * **osmium-add-locations-to-ways**(1), **osmium-apply-changes**(1), **osmium-cat**(1), **osmium-changeset-filter**(1), **osmium-check-refs**(1), **osmium-derive-changes**(1), **osmium-diff**(1), **osmium-export**(1), **osmium-extract**(1), **osmium-fileinfo**(1), **osmium-getid**(1), **osmium-merge**(1), **osmium-merge-changes**(1), **osmium-renumber**(1), **osmium-show**(1), **osmium-sort**(1), **osmium-tags-filter**(1), **osmium-time-filter**(1), **osmium-file-formats**(5) * [Osmium website](http://osmcode.org/osmium-tool/) osmium-tool-1.7.1/man/output-options.md000066400000000000000000000016201315004223400201230ustar00rootroot00000000000000 # OUTPUT OPTIONS -f, --output-format=FORMAT : The format of the output file. Can be used to set the output file format if it can't be autodetected from the output file name. See **osmium-file-formats**(5) or the libosmium manual for details. --fsync : Call fsync after writing the output file to force flushing buffers to disk. --generator=NAME : The name and version of the program generating the output file. It will be added to the header of the output file. Default is "*osmium/*" and the version of osmium. -o, --output=FILE : Name of the output file. Default is '-' (STDOUT). -O, --overwrite : Allow an existing output file to be overwritten. Normally **osmium** will refuse to write over an existing file. --output-header=OPTION : Add output header option. This option can be given several times. See the *libosmium manual* for a list of allowed header options. osmium-tool-1.7.1/man/progress-options.md000066400000000000000000000007761315004223400204420ustar00rootroot00000000000000 --progress : Show progress bar. Usually a progress bar is only displayed if STDERR is detected to be a TTY. With this option a progress bar is always shown. Note that a progress bar will never be shown when reading from STDIN or a pipe. --no-progress : Do not show progress bar. Usually a progress bar is displayed if STDERR is detected to be a TTY. With this option the progress bar is suppressed. Note that a progress bar will never be shown when reading from STDIN or a pipe. osmium-tool-1.7.1/osmium-wrapper.in000077500000000000000000000007531315004223400173250ustar00rootroot00000000000000#!/bin/sh #----------------------------------------------------------------------------- # # This is a small wrapper for the osmium binary that is only used to call it # from the build directory, ie when it is not installed. It sets the MANPATH # so the help facility will work and then calls the osmium proper. # #----------------------------------------------------------------------------- export MANPATH=$MANPATH:@PROJECT_BINARY_DIR@/man: exec @PROJECT_BINARY_DIR@/src/osmium "$@" osmium-tool-1.7.1/scripts/000077500000000000000000000000001315004223400154655ustar00rootroot00000000000000osmium-tool-1.7.1/scripts/osm-history-splitter2osmium-extract-config.sh000077500000000000000000000012761315004223400264220ustar00rootroot00000000000000#!/bin/sh # # Convert a config file in the format for the osm-history-splitter into a # config file for the "osmium extract" command. # if [ -n "$1" ]; then exec <$1 fi echo '{' echo ' "extracts": [' while read output type region; do echo ' {' echo " \"output\": \"$output\"," if [ "$type" = "BBOX" ]; then echo " \"bbox\": [$region]" elif [ "$type" = "OSM" -o "$type" = "POLY" ]; then lctype=`echo $type | tr 'A-Z' 'a-z'` cat << __END__ "polygon": { "file_name": "$region", "file_type": "$lctype" } __END__ fi echo ' },' done echo ' ]' echo '}' osmium-tool-1.7.1/src/000077500000000000000000000000001315004223400145655ustar00rootroot00000000000000osmium-tool-1.7.1/src/CMakeLists.txt000066400000000000000000000026741315004223400173360ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool # #----------------------------------------------------------------------------- set(OSMIUM_SOURCE_FILES ${PROJECT_BINARY_DIR}/src/version.cpp cmd.cpp cmd_factory.cpp io.cpp main.cpp util.cpp command_add_locations_to_ways.cpp command_apply_changes.cpp command_cat.cpp command_changeset_filter.cpp command_check_refs.cpp command_derive_changes.cpp command_diff.cpp command_export.cpp command_extract.cpp command_fileinfo.cpp command_getid.cpp command_help.cpp command_merge_changes.cpp command_merge.cpp command_renumber.cpp commands.cpp command_show.cpp command_sort.cpp command_tags_filter.cpp command_time_filter.cpp export/export_format_json.cpp export/export_format_text.cpp export/export_handler.cpp extract/extract_bbox.cpp extract/extract.cpp extract/extract_polygon.cpp extract/geojson_file_parser.cpp extract/osm_file_parser.cpp extract/poly_file_parser.cpp extract/strategy_complete_ways.cpp extract/strategy_complete_ways_with_history.cpp extract/strategy_simple.cpp extract/strategy_smart.cpp ) add_executable(osmium ${OSMIUM_SOURCE_FILES}) target_link_libraries(osmium ${Boost_LIBRARIES} ${OSMIUM_LIBRARIES}) set_pthread_on_target(osmium) install(TARGETS osmium DESTINATION bin) osmium-tool-1.7.1/src/cmd.cpp000066400000000000000000000121621315004223400160360ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include "cmd.hpp" #include "exception.hpp" po::options_description Command::add_common_options(bool with_progress) { po::options_description options("COMMON OPTIONS"); auto opts = options.add_options() ("help,h", "Show usage help") ("verbose,v", "Set verbose mode") ; if (with_progress) { opts("progress", "Display progress bar") ("no-progress", "Suppress display of progress bar"); } return options; } void Command::setup_common(const boost::program_options::variables_map& vm, const po::options_description& desc) { if (vm.count("help")) { std::cout << "Usage: " << synopsis() << "\n\n" << CommandFactory::get_description(name()) << "\n" << desc << "\nUse 'osmium help " << name() << "' to display the manual page.\n"; std::exit(0); } if (vm.count("verbose")) { m_vout.verbose(true); } } void Command::setup_progress(const boost::program_options::variables_map& vm) { if (vm.count("progress") && vm.count("no-progress")) { throw argument_error{"Can not use --progress and --no-progress together."}; } if (vm.count("progress")) { m_display_progress = display_progress_type::always; } if (vm.count("no-progress")) { m_display_progress = display_progress_type::never; } } void Command::setup_object_type_nwrc(const boost::program_options::variables_map& vm) { if (vm.count("object-type")) { m_osm_entity_bits = osmium::osm_entity_bits::nothing; for (const auto& t : vm["object-type"].as>()) { if (t == "n" || t == "node") { m_osm_entity_bits |= osmium::osm_entity_bits::node; } else if (t == "w" || t == "way") { m_osm_entity_bits |= osmium::osm_entity_bits::way; } else if (t == "r" || t == "relation") { m_osm_entity_bits |= osmium::osm_entity_bits::relation; } else if (t == "c" || t == "changeset") { m_osm_entity_bits |= osmium::osm_entity_bits::changeset; } else { throw argument_error{std::string{"Unknown object type '"} + t + "' (Allowed are 'node', 'way', 'relation', and 'changeset')."}; } } } else { m_osm_entity_bits = osmium::osm_entity_bits::all; } } void Command::setup_object_type_nwr(const boost::program_options::variables_map& vm) { if (vm.count("object-type")) { m_osm_entity_bits = osmium::osm_entity_bits::nothing; for (const auto& t : vm["object-type"].as>()) { if (t == "n" || t == "node") { m_osm_entity_bits |= osmium::osm_entity_bits::node; } else if (t == "w" || t == "way") { m_osm_entity_bits |= osmium::osm_entity_bits::way; } else if (t == "r" || t == "relation") { m_osm_entity_bits |= osmium::osm_entity_bits::relation; } else { throw argument_error{std::string{"Unknown object type '"} + t + "' (Allowed are 'node', 'way', and 'relation')."}; } } } else { m_osm_entity_bits = osmium::osm_entity_bits::nwr; } } void Command::show_object_types(osmium::util::VerboseOutput& vout) { vout << " object types:"; if (osm_entity_bits() & osmium::osm_entity_bits::node) { vout << " node"; } if (osm_entity_bits() & osmium::osm_entity_bits::way) { vout << " way"; } if (osm_entity_bits() & osmium::osm_entity_bits::relation) { vout << " relation"; } if (osm_entity_bits() & osmium::osm_entity_bits::changeset) { vout << " changeset"; } m_vout << '\n'; } void Command::print_arguments(const std::string& command) { if (m_vout.verbose()) { m_vout << "Started osmium " << command << '\n' << " " << get_osmium_long_version() << '\n' << " " << get_libosmium_version() << '\n' << "Command line options and default settings:\n"; show_arguments(); } } void Command::show_memory_used() { osmium::MemoryUsage mem; if (mem.current() > 0) { m_vout << "Peak memory used: " << mem.peak() << " MBytes\n"; } } osmium-tool-1.7.1/src/cmd.hpp000066400000000000000000000164771315004223400160600ustar00rootroot00000000000000#ifndef CMD_HPP #define CMD_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include namespace po = boost::program_options; #include #include #include #include #include const char* get_osmium_version() noexcept; const char* get_osmium_long_version() noexcept; const char* get_libosmium_version() noexcept; namespace osmium { namespace io { class Header; }} /** * Virtual base class for commands that can be called from the command line. */ class Command { osmium::osm_entity_bits::type m_osm_entity_bits {osmium::osm_entity_bits::all}; enum class display_progress_type { never = 0, on_tty = 1, always = 2 } m_display_progress = display_progress_type::on_tty; protected: osmium::util::VerboseOutput m_vout {false}; public: Command() = default; virtual ~Command() { } // This function parses the command line arguments for a // command. // It returns true if the parsing was successful and the run() // function should be called. It returns false if the work is // done and run() should not be called. // It throws if there was a problem with the arguments. // // This function should not attempt to open any files or // do any other actual work. That will happen in the run() // function. virtual bool setup(const std::vector&) { return true; } // Show command line arguments. This is only called when the // verbose option is true; virtual void show_arguments() { } // Run the actual command. // It returns true if everything ran successfully. // It returns false if there was an error. virtual bool run() = 0; // The name of the command. virtual const char* name() const noexcept = 0; // The command line usage synopsis of the command. virtual const char* synopsis() const noexcept = 0; po::options_description add_common_options(bool with_progress = true); void setup_common(const boost::program_options::variables_map& vm, const po::options_description& desc); void setup_progress(const boost::program_options::variables_map& vm); void setup_object_type_nwrc(const boost::program_options::variables_map& vm); void setup_object_type_nwr(const boost::program_options::variables_map& vm); void show_object_types(osmium::util::VerboseOutput& vout); void print_arguments(const std::string& command); void show_memory_used(); osmium::osm_entity_bits::type osm_entity_bits() const { return m_osm_entity_bits; } bool display_progress() const { switch (m_display_progress) { case display_progress_type::on_tty: return osmium::util::isatty(2); // if STDERR is a TTY case display_progress_type::always: return true; default: break; } return false; } }; // class Command class with_single_osm_input { protected: std::string m_input_filename; std::string m_input_format; osmium::io::File m_input_file; public: void setup_input_file(const boost::program_options::variables_map& vm); po::options_description add_single_input_options(); void show_single_input_arguments(osmium::util::VerboseOutput& vout); const osmium::io::File& input_file() const { return m_input_file; } }; // class with_single_osm_input class with_multiple_osm_inputs { protected: std::vector m_input_filenames; std::string m_input_format; std::vector m_input_files; public: void setup_input_files(const boost::program_options::variables_map& vm); po::options_description add_multiple_inputs_options(); void show_multiple_inputs_arguments(osmium::util::VerboseOutput& vout); const std::vector& input_files() const { return m_input_files; } }; // class with_multiple_osm_inputs class with_osm_output { protected: std::string m_generator; std::vector m_output_headers; std::string m_output_filename; std::string m_output_format; osmium::io::File m_output_file; osmium::io::overwrite m_output_overwrite = osmium::io::overwrite::no; osmium::io::fsync m_fsync = osmium::io::fsync::no; public: with_osm_output() : m_generator("osmium/") { m_generator.append(get_osmium_version()); } void init_output_file(const po::variables_map& vm); void check_output_file(); void setup_output_file(const po::variables_map& vm); po::options_description add_output_options(); void show_output_arguments(osmium::util::VerboseOutput& vout); const osmium::io::File& output_file() const { return m_output_file; } void setup_header(osmium::io::Header& header) const; osmium::io::overwrite output_overwrite() const { return m_output_overwrite; } }; // class with_osm_output /** * All commands than can be called from the command line are registered * with this factory. When the program is running it uses this factory * to create the command object from the class depending on the name of * the command. */ class CommandFactory { using create_command_type = std::function; struct command_info { std::string description; // description of command for help create_command_type create; // function that creates C++ object }; std::map m_commands; // The constructor is private because CommandFactory is a singleton CommandFactory() : m_commands() { } public: // CommandFactory is a singleton, this returns the only instance static CommandFactory& instance(); // Return a vector with names and descriptions of all commands static std::vector> help(); static int max_command_name_length(); static bool add(const std::string& name, const std::string& description, create_command_type create_function); static std::string get_description(const std::string& name); bool register_command(const std::string& name, const std::string& description, create_command_type create_function); // This will create a C++ command object from the given name and // return it wrapped in a unique_ptr. std::unique_ptr create_command(const std::string& name); }; // class CommandFactory void register_commands(); #endif // CMD_HPP osmium-tool-1.7.1/src/cmd_factory.cpp000066400000000000000000000046571315004223400175770ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include "cmd.hpp" CommandFactory& CommandFactory::instance() { static CommandFactory factory; return factory; } std::vector> CommandFactory::help() { std::vector> commands; for (const auto& cmd : instance().m_commands) { commands.push_back(std::make_pair(cmd.first, cmd.second.description)); } return commands; } int CommandFactory::max_command_name_length() { osmium::max_op max_width; for (const auto& cmd : instance().m_commands) { max_width.update(int(cmd.first.length())); } return max_width(); } bool CommandFactory::add(const std::string& name, const std::string& description, create_command_type create_function) { return instance().register_command(name, description, create_function); } std::string CommandFactory::get_description(const std::string& name) { auto it = instance().m_commands.find(name); if (it == instance().m_commands.end()) { return ""; } return it->second.description; } bool CommandFactory::register_command(const std::string& name, const std::string& description, create_command_type create_function) { command_info info {description, create_function}; return m_commands.insert(std::make_pair(name, info)).second; } std::unique_ptr CommandFactory::create_command(const std::string& name) { const auto it = m_commands.find(name); if (it != m_commands.end()) { return std::unique_ptr((it->second.create)()); } return std::unique_ptr(); } osmium-tool-1.7.1/src/command_add_locations_to_ways.cpp000066400000000000000000000147251315004223400233500ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_add_locations_to_ways.hpp" #include "exception.hpp" #include "util.hpp" bool CommandAddLocationsToWays::setup(const std::vector& arguments) { const auto& map_factory = osmium::index::MapFactory::instance(); std::string default_index_type{"flex_mem"}; po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("index-type,i", po::value()->default_value(default_index_type), "Index type to use") ("show-index-types,I", "Show available index types") ("keep-untagged-nodes,n", "Keep untagged nodes") ("ignore-missing-nodes", "Ignore missing nodes") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_multiple_inputs_options()}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("input-filenames", po::value>(), "Input files") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filenames", -1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); if (vm.count("show-index-types")) { for (const auto& map_type : map_factory.map_types()) { std::cout << map_type << '\n'; } return false; } if (vm.count("index-type")) { m_index_type_name = vm["index-type"].as(); if (!map_factory.has_map_type(m_index_type_name)) { throw argument_error{std::string{"Unknown index type '"} + m_index_type_name + "'. Use --show-index-types or -I to get a list."}; } } setup_common(vm, desc); setup_progress(vm); setup_input_files(vm); setup_output_file(vm); if (vm.count("keep-untagged-nodes")) { m_keep_untagged_nodes = true; } if (vm.count("ignore-missing-nodes")) { m_ignore_missing_nodes = true; } return true; } void CommandAddLocationsToWays::show_arguments() { show_multiple_inputs_arguments(m_vout); show_output_arguments(m_vout); m_vout << " other options:\n"; m_vout << " index type: " << m_index_type_name << '\n'; m_vout << " keep untagged nodes: " << yes_no(m_keep_untagged_nodes); m_vout << '\n'; } void CommandAddLocationsToWays::copy_data(osmium::ProgressBar& progress_bar, osmium::io::Reader& reader, osmium::io::Writer& writer, location_handler_type& location_handler) { while (osmium::memory::Buffer buffer = reader.read()) { progress_bar.update(reader.offset()); osmium::apply(buffer, location_handler); if (m_keep_untagged_nodes) { writer(std::move(buffer)); } else { for (const auto& object : buffer) { if (object.type() != osmium::item_type::node || !static_cast(object).tags().empty()) { writer(object); } } } } } bool CommandAddLocationsToWays::run() { const auto& map_factory = osmium::index::MapFactory::instance(); auto location_index = map_factory.create_map(m_index_type_name); location_handler_type location_handler{*location_index}; if (m_ignore_missing_nodes) { location_handler.ignore_errors(); } m_output_file.set("locations_on_ways"); if (m_input_files.size() == 1) { // single input file m_vout << "Copying input file '" << m_input_files[0].filename() << "'\n"; osmium::io::Reader reader{m_input_files[0]}; osmium::io::Header header{reader.header()}; setup_header(header); osmium::io::Writer writer(m_output_file, header, m_output_overwrite, m_fsync); osmium::ProgressBar progress_bar{reader.file_size(), display_progress()}; copy_data(progress_bar, reader, writer, location_handler); progress_bar.done(); writer.close(); reader.close(); } else { // multiple input files osmium::io::Header header; setup_header(header); osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; osmium::ProgressBar progress_bar{file_size_sum(m_input_files), display_progress()}; for (const auto& input_file : m_input_files) { progress_bar.remove(); m_vout << "Copying input file '" << input_file.filename() << "'\n"; osmium::io::Reader reader(input_file); copy_data(progress_bar, reader, writer, location_handler); progress_bar.file_done(reader.file_size()); reader.close(); } progress_bar.done(); writer.close(); } m_vout << "About " << (location_index->used_memory() / (1024 * 1024)) << " MBytes used for node location index (in main memory or on disk).\n"; show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_add_locations_to_ways.hpp000066400000000000000000000042551315004223400233520ustar00rootroot00000000000000#ifndef COMMAND_ADD_LOCATIONS_TO_WAYS_HPP #define COMMAND_ADD_LOCATIONS_TO_WAYS_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include namespace osmium { namespace io { class Reader; class Writer; } class ProgressBar; } #include "cmd.hpp" // IWYU pragma: export using index_type = osmium::index::map::Map; using location_handler_type = osmium::handler::NodeLocationsForWays; class CommandAddLocationsToWays : public Command, public with_multiple_osm_inputs, public with_osm_output { void copy_data(osmium::ProgressBar& progress_bar, osmium::io::Reader& reader, osmium::io::Writer& writer, location_handler_type& location_handler); std::string m_index_type_name; bool m_keep_untagged_nodes = false; bool m_ignore_missing_nodes = false; public: CommandAddLocationsToWays() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "add-locations-to-ways"; } const char* synopsis() const noexcept override final { return "osmium add-locations-to-ways [OPTIONS] OSM-FILE..."; } }; // class CommandAddLocationsToWays #endif // COMMAND_ADD_LOCATIONS_TO_WAYS_HPP osmium-tool-1.7.1/src/command_apply_changes.cpp000066400000000000000000000316711315004223400216140ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_apply_changes.hpp" #include "exception.hpp" #include "util.hpp" using location_index_type = osmium::index::map::SparseMemArray; bool CommandApplyChanges::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("change-file-format", po::value(), "Format of the change file(s)") ("simplify,s", "Simplify change (deprecated)") ("remove-deleted,r", "Remove deleted objects from output (deprecated)") ("with-history,H", "Apply changes to history file") ("locations-on-ways", "Expect and update locations on ways") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_single_input_options()}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("input-filename", po::value(), "OSM input file") ("change-filenames", po::value>(), "OSM change input files") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filename", 1); positional.add("change-filenames", -1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_input_file(vm); setup_output_file(vm); if (vm.count("change-filenames")) { m_change_filenames = vm["change-filenames"].as>(); } else { throw argument_error{"Need data file and at least one change file on the command line."}; } if (vm.count("change-file-format")) { m_change_file_format = vm["change-file-format"].as(); } if (vm.count("locations-on-ways")) { m_locations_on_ways = true; } if (vm.count("with-history")) { if (m_locations_on_ways) { throw argument_error{"Can not use --with-history/-H and --locations-on-ways together."}; } m_with_history = true; m_output_file.set_has_multiple_object_versions(true); } else { if (m_input_file.has_multiple_object_versions() && m_output_file.has_multiple_object_versions()) { m_with_history = true; } else if (m_input_file.has_multiple_object_versions() != m_output_file.has_multiple_object_versions()) { throw argument_error{"Input and output file must both be OSM data files or both OSM history files (force with --with-history)."}; } } if (vm.count("simplify")) { warning("-s, --simplify option is deprecated. Please see manual page.\n"); m_with_history = false; } if (vm.count("remove-deleted")) { warning("-r, --remove-deleted option is deprecated. Please see manual page.\n"); m_with_history = false; } return true; } void CommandApplyChanges::show_arguments() { m_vout << " input data file name: " << m_input_filename << "\n"; m_vout << " input change file names: \n"; for (const auto& fn : m_change_filenames) { m_vout << " " << fn << "\n"; } m_vout << " data file format: " << m_input_format << "\n"; m_vout << " change file format: " << m_change_file_format << "\n"; show_output_arguments(m_vout); m_vout << " reading and writing history file: " << yes_no(m_with_history); m_vout << " locations on ways: " << yes_no(m_locations_on_ways); } namespace { /** * Copy the first OSM object with a given Id to the output. Keep * track of the Id of each object to do this. * * We are using this functor class instead of a simple lambda, because the * lambda doesn't build on MSVC. */ class copy_first_with_id { osmium::io::Writer* writer; osmium::object_id_type id = 0; public: explicit copy_first_with_id(osmium::io::Writer& w) : writer(&w) { } void operator()(const osmium::OSMObject& obj) { if (obj.id() != id) { if (obj.visible()) { (*writer)(obj); } id = obj.id(); } } }; // class copy_first_with_id } // anonymous namespace static void update_nodes_if_way(osmium::OSMObject& object, const location_index_type& location_index) { if (object.type() != osmium::item_type::way) { return; } for (auto& node_ref : static_cast(object).nodes()) { auto location = location_index.get_noexcept(node_ref.positive_ref()); if (location) { node_ref.set_location(location); } } } bool CommandApplyChanges::run() { std::vector changes; osmium::ObjectPointerCollection objects; m_vout << "Reading change file contents...\n"; for (const std::string& change_file_name : m_change_filenames) { if (change_file_name == "-" && m_change_file_format.empty()) { throw argument_error{"When reading the change file from STDIN you have to use\n" "the --change-file-format option to specify the file format."}; } osmium::io::File file{change_file_name, m_change_file_format}; osmium::io::Reader reader{file, osmium::osm_entity_bits::object}; while (osmium::memory::Buffer buffer = reader.read()) { osmium::apply(buffer, objects); changes.push_back(std::move(buffer)); } reader.close(); } m_vout << "Opening input file...\n"; osmium::io::Reader reader{m_input_file, osmium::osm_entity_bits::object}; osmium::io::Header header; setup_header(header); if (m_with_history) { header.set_has_multiple_object_versions(true); } if (m_locations_on_ways) { m_output_file.set("locations_on_ways"); } m_vout << "Opening output file...\n"; osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; if (m_with_history) { // For history files this is a straightforward sort of the change // files followed by a merge with the input file. m_vout << "Sorting change data...\n"; objects.sort(osmium::object_order_type_id_version()); const auto input = osmium::io::make_input_iterator_range(reader); auto out = osmium::io::make_output_iterator(writer); m_vout << "Applying changes and writing them to output...\n"; std::set_union(objects.begin(), objects.end(), input.begin(), input.end(), out); } else { // For normal data files we sort with the largest version of each // object first and then only copy this last version of any object // to the output. m_vout << "Sorting change data...\n"; objects.sort(osmium::object_order_type_id_reverse_version{}); if (m_locations_on_ways) { objects.unique(osmium::object_equal_type_id{}); m_vout << "There are " << objects.size() << " unique objects in the change files\n"; osmium::index::IdSetSmall node_ids; m_vout << "Creating node index...\n"; for (const auto& buffer : changes) { for (const auto& way : buffer.select()) { for (const auto& nr : way.nodes()) { node_ids.set(nr.positive_ref()); } } } node_ids.sort_unique(); m_vout << "Node index has " << node_ids.size() << " entries\n"; m_vout << "Creating location index...\n"; location_index_type location_index; for (const auto& buffer : changes) { for (const auto& node : buffer.select()) { location_index.set(node.positive_id(), node.location()); } } m_vout << "Location index has " << location_index.size() << " entries\n"; m_vout << "Applying changes and writing them to output...\n"; auto it = objects.begin(); auto last_type = osmium::item_type::undefined; osmium::ProgressBar progress_bar{reader.file_size(), display_progress()}; while (osmium::memory::Buffer buffer = reader.read()) { progress_bar.update(reader.offset()); for (auto& object : buffer.select()) { if (object.type() < last_type) { throw std::runtime_error{"Input data out of order. Need nodes, ways, relations in ID order."}; } if (object.type() == osmium::item_type::node) { const auto& node = static_cast(object); if (node_ids.get_binary_search(node.positive_id())) { const auto location = location_index.get_noexcept(node.positive_id()); if (!location) { location_index.set(node.positive_id(), node.location()); } } } else if (object.type() == osmium::item_type::way) { if (last_type == osmium::item_type::node) { location_index.sort(); node_ids.clear(); } } last_type = object.type(); auto last_it = it; while (it != objects.end() && osmium::object_order_type_id_reverse_version{}(*it, object)) { if (it->visible()) { update_nodes_if_way(*it, location_index); writer(*it); } last_it = it; ++it; } if (last_it == objects.end() || last_it->type() != object.type() || last_it->id() != object.id()) { update_nodes_if_way(object, location_index); writer(object); } } } while (it != objects.end()) { if (it->visible()) { update_nodes_if_way(*it, location_index); writer(*it); } ++it; } progress_bar.done(); } else { const auto input = osmium::io::make_input_iterator_range(reader); auto output_it = boost::make_function_output_iterator( copy_first_with_id(writer) ); m_vout << "Applying changes and writing them to output...\n"; std::set_union(objects.begin(), objects.end(), input.begin(), input.end(), output_it, osmium::object_order_type_id_reverse_version()); } } writer.close(); reader.close(); show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_apply_changes.hpp000066400000000000000000000032251315004223400216130ustar00rootroot00000000000000#ifndef COMMAND_APPLY_CHANGES_HPP #define COMMAND_APPLY_CHANGES_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "cmd.hpp" // IWYU pragma: export class CommandApplyChanges : public Command, public with_single_osm_input, public with_osm_output { std::vector m_change_filenames; std::string m_change_file_format; bool m_with_history = false; bool m_locations_on_ways = false; public: CommandApplyChanges() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "apply-changes"; } const char* synopsis() const noexcept override final { return "osmium apply-changes [OPTIONS] OSM-FILE OSM-CHANGE-FILE..."; } }; // class CommandApplyChanges #endif // COMMAND_APPLY_CHANGES_HPP osmium-tool-1.7.1/src/command_cat.cpp000066400000000000000000000102141315004223400175340ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include "command_cat.hpp" #include "util.hpp" bool CommandCat::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("object-type,t", po::value>(), "Read only objects of given type (node, way, relation, changeset)") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_multiple_inputs_options()}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("input-filenames", po::value>(), "Input files") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filenames", -1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_progress(vm); setup_object_type_nwrc(vm); setup_input_files(vm); setup_output_file(vm); return true; } void CommandCat::show_arguments() { show_multiple_inputs_arguments(m_vout); show_output_arguments(m_vout); m_vout << " other options:\n"; show_object_types(m_vout); } bool CommandCat::run() { if (m_input_files.size() == 1) { // single input file m_vout << "Copying input file '" << m_input_files[0].filename() << "'\n"; osmium::io::Reader reader{m_input_files[0], osm_entity_bits()}; osmium::io::Header header{reader.header()}; setup_header(header); osmium::io::Writer writer(m_output_file, header, m_output_overwrite, m_fsync); osmium::ProgressBar progress_bar{reader.file_size(), display_progress()}; while (osmium::memory::Buffer buffer = reader.read()) { progress_bar.update(reader.offset()); writer(std::move(buffer)); } progress_bar.done(); writer.close(); reader.close(); } else { // multiple input files osmium::io::Header header; setup_header(header); osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; osmium::ProgressBar progress_bar{file_size_sum(m_input_files), display_progress()}; for (const auto& input_file : m_input_files) { progress_bar.remove(); m_vout << "Copying input file '" << input_file.filename() << "'\n"; osmium::io::Reader reader{input_file, osm_entity_bits()}; while (osmium::memory::Buffer buffer = reader.read()) { progress_bar.update(reader.offset()); writer(std::move(buffer)); } progress_bar.file_done(reader.file_size()); reader.close(); } writer.close(); progress_bar.done(); } show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_cat.hpp000066400000000000000000000026321315004223400175460ustar00rootroot00000000000000#ifndef COMMAND_CAT_HPP #define COMMAND_CAT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "cmd.hpp" // IWYU pragma: export class CommandCat : public Command, public with_multiple_osm_inputs, public with_osm_output { public: CommandCat() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "cat"; } const char* synopsis() const noexcept override final { return "osmium cat [OPTIONS] OSM-FILE..."; } }; // class CommandCat #endif // COMMAND_CAT_HPP osmium-tool-1.7.1/src/command_changeset_filter.cpp000066400000000000000000000202761315004223400223040ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_changeset_filter.hpp" #include "exception.hpp" #include "util.hpp" bool CommandChangesetFilter::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("with-discussion,d", "Changesets with discussions (comments)") ("without-discussion,D", "Changesets without discussions (no comments)") ("with-changes,c", "Changesets with changes") ("without-changes,C", "Changesets without any changes") ("open", "Open changesets") ("closed", "Closed changesets") ("user,u", po::value(), "Changesets by given user") ("uid,U", po::value(), "Changesets by given user ID") ("after,a", po::value(), "Changesets opened after this time") ("before,b", po::value(), "Changesets closed before this time") ("bbox,B", po::value(), "Changesets overlapping this bounding box") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_single_input_options()}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("input-filename", po::value(), "OSM input file") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filename", 1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_progress(vm); setup_input_file(vm); setup_output_file(vm); if (vm.count("with-discussion")) { m_with_discussion = true; } if (vm.count("without-discussion")) { m_without_discussion = true; } if (vm.count("with-changes")) { m_with_changes = true; } if (vm.count("without-changes")) { m_without_changes = true; } if (vm.count("open")) { m_open = true; } if (vm.count("closed")) { m_closed = true; } if (vm.count("uid")) { m_uid = vm["uid"].as(); } if (vm.count("user")) { m_user = vm["user"].as(); } if (vm.count("after")) { auto ts = vm["after"].as(); try { m_after = osmium::Timestamp(ts); } catch (const std::invalid_argument&) { throw argument_error{"Wrong format for --after/-a timestamp (use YYYY-MM-DDThh:mm:ssZ)."}; } } if (vm.count("before")) { auto ts = vm["before"].as(); try { m_before = osmium::Timestamp(ts); } catch (const std::invalid_argument&) { throw argument_error{"Wrong format for --before/-b timestamp (use YYYY-MM-DDThh:mm:ssZ)."}; } } if (vm.count("bbox")) { m_box = parse_bbox(vm["bbox"].as(), "--bbox/-B"); } if (m_with_discussion && m_without_discussion) { throw argument_error{"You can not use --with-discussion/-d and --without-discussion/-D together."}; } if (m_with_changes && m_without_changes) { throw argument_error{"You can not use --with-changes/-c and --without-changes/-C together."}; } if (m_open && m_closed) { throw argument_error{"You can not use --open and --closed together."}; } if (m_after > m_before) { throw argument_error{"Timestamp 'after' is after 'before'."}; } return true; } void CommandChangesetFilter::show_arguments() { show_single_input_arguments(m_vout); show_output_arguments(m_vout); m_vout << " other options:\n"; m_vout << " changesets must\n"; if (m_with_discussion) { m_vout << " - have a discussion\n"; } if (m_without_discussion) { m_vout << " - not have a discussion\n"; } if (m_with_changes) { m_vout << " - have at least one change\n"; } if (m_without_changes) { m_vout << " - not have any changes\n"; } if (m_open) { m_vout << " - be open\n"; } if (m_closed) { m_vout << " - be closed\n"; } if (m_uid != 0) { m_vout << " - be from uid " << m_uid << "\n"; } if (!m_user.empty()) { m_vout << " - be from user '" << m_user << "'\n"; } if (m_after > osmium::start_of_time()) { m_vout << " - be closed after " << m_after.to_iso() << " or still open\n"; } if (m_before < osmium::end_of_time()) { m_vout << " - be created before " << m_before.to_iso() << "\n"; } } bool changeset_after(const osmium::Changeset& changeset, osmium::Timestamp time) { return changeset.open() || changeset.closed_at() >= time; } bool changeset_before(const osmium::Changeset& changeset, osmium::Timestamp time) { return changeset.created_at() <= time; } bool CommandChangesetFilter::run() { m_vout << "Opening input file...\n"; osmium::io::Reader reader{m_input_file, osmium::osm_entity_bits::changeset}; auto input = osmium::io::make_input_iterator_range(reader); osmium::io::Header header{reader.header()}; setup_header(header); m_vout << "Opening output file...\n"; osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; auto out = osmium::io::make_output_iterator(writer); m_vout << "Filtering data...\n"; osmium::ProgressBar progress_bar{reader.file_size(), display_progress()}; int count = 0; std::copy_if(input.begin(), input.end(), out, [this, &count, &progress_bar, &reader](const osmium::Changeset& changeset) { if (++count > 10000) { progress_bar.update(reader.offset()); count = 0; } return (!m_with_discussion || changeset.num_comments() > 0) && (!m_without_discussion || changeset.num_comments() == 0) && (!m_with_changes || changeset.num_changes() > 0) && (!m_without_changes || changeset.num_changes() == 0) && (!m_open || changeset.open()) && (!m_closed || changeset.closed()) && (m_uid == 0 || changeset.uid() == m_uid) && (m_user.empty() || m_user == changeset.user()) && changeset_after(changeset, m_after) && changeset_before(changeset, m_before) && (!m_box.valid() || (changeset.bounds().valid() && osmium::geom::overlaps(changeset.bounds(), m_box))); }); progress_bar.done(); writer.close(); reader.close(); show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_changeset_filter.hpp000066400000000000000000000037211315004223400223050ustar00rootroot00000000000000#ifndef COMMAND_CHANGESET_FILTER_HPP #define COMMAND_CHANGESET_FILTER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "cmd.hpp" // IWYU pragma: export class CommandChangesetFilter : public Command, public with_single_osm_input, public with_osm_output { bool m_with_discussion = false; bool m_without_discussion = false; bool m_with_changes = false; bool m_without_changes = false; bool m_open = false; bool m_closed = false; osmium::user_id_type m_uid = 0; std::string m_user; osmium::Timestamp m_after = osmium::start_of_time(); osmium::Timestamp m_before = osmium::end_of_time(); osmium::Box m_box; public: CommandChangesetFilter() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "changeset-filter"; } const char* synopsis() const noexcept override final { return "osmium changeset-filter [OPTIONS] OSM-CHANGESET-FILE"; } }; // class CommandChangesetFilter #endif // COMMAND_CHANGESET_FILTER_HPP osmium-tool-1.7.1/src/command_check_refs.cpp000066400000000000000000000244261315004223400210730ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_check_refs.hpp" #include "util.hpp" bool CommandCheckRefs::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("show-ids,i", "Show IDs of missing objects") ("check-relations,r", "Also check relations") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_single_input_options()}; po::options_description hidden; hidden.add_options() ("input-filename", po::value(), "Input file") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filename", 1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_progress(vm); setup_input_file(vm); if (vm.count("show-ids")) { m_show_ids = true; } if (vm.count("check-relations")) { m_check_relations = true; } return true; } void CommandCheckRefs::show_arguments() { show_single_input_arguments(m_vout); m_vout << " other options:\n"; m_vout << " show ids: " << yes_no(m_show_ids); m_vout << " check relations: " << yes_no(m_check_relations); } class RefCheckHandler : public osmium::handler::Handler { osmium::nwr_array> m_idset_pos; osmium::nwr_array> m_idset_neg; std::vector> m_relation_refs; osmium::handler::CheckOrder m_check_order; uint64_t m_node_count = 0; uint64_t m_way_count = 0; uint64_t m_relation_count = 0; uint64_t m_missing_nodes_in_ways = 0; uint64_t m_missing_nodes_in_relations = 0; uint64_t m_missing_ways_in_relations = 0; osmium::util::VerboseOutput& m_vout; osmium::ProgressBar& m_progress_bar; bool m_show_ids; bool m_check_relations; void set(osmium::item_type type, osmium::object_id_type id) { (id > 0 ? m_idset_pos(type) : m_idset_neg(type)).set(std::abs(id)); } bool get(osmium::item_type type, osmium::object_id_type id) const noexcept { return (id > 0 ? m_idset_pos(type) : m_idset_neg(type)).get(std::abs(id)); } public: RefCheckHandler(osmium::util::VerboseOutput& vout, osmium::ProgressBar& progress_bar, bool show_ids, bool check_relations) : m_vout(vout), m_progress_bar(progress_bar), m_show_ids(show_ids), m_check_relations(check_relations) { } uint64_t node_count() const { return m_node_count; } uint64_t way_count() const { return m_way_count; } uint64_t relation_count() const { return m_relation_count; } uint64_t missing_nodes_in_ways() const { return m_missing_nodes_in_ways; } uint64_t missing_nodes_in_relations() const { return m_missing_nodes_in_relations; } uint64_t missing_ways_in_relations() const { return m_missing_ways_in_relations; } uint64_t missing_relations_in_relations() const { return m_relation_refs.size(); } void find_missing_relations() { std::sort(m_relation_refs.begin(), m_relation_refs.end()); m_relation_refs.erase( std::remove_if(m_relation_refs.begin(), m_relation_refs.end(), [this](std::pair refs){ return get(osmium::item_type::relation, refs.first); }), m_relation_refs.end() ); } bool no_errors() { return missing_nodes_in_ways() == 0 && missing_nodes_in_relations() == 0 && missing_ways_in_relations() == 0 && missing_relations_in_relations() == 0; } void node(const osmium::Node& node) { m_check_order.node(node); if (m_node_count == 0) { m_progress_bar.remove(); m_vout << "Reading nodes...\n"; } ++m_node_count; set(osmium::item_type::node, node.id()); } void way(const osmium::Way& way) { m_check_order.way(way); if (m_way_count == 0) { m_progress_bar.remove(); m_vout << "Reading ways...\n"; } ++m_way_count; if (m_check_relations) { set(osmium::item_type::way, way.id()); } for (const auto& node_ref : way.nodes()) { if (!get(osmium::item_type::node, node_ref.ref())) { ++m_missing_nodes_in_ways; if (m_show_ids) { std::cout << "n" << node_ref.ref() << " in w" << way.id() << "\n"; } } } } void relation(const osmium::Relation& relation) { m_check_order.relation(relation); if (m_relation_count == 0) { m_progress_bar.remove(); m_vout << "Reading relations...\n"; } ++m_relation_count; if (m_check_relations) { set(osmium::item_type::relation, relation.id()); for (const auto& member : relation.members()) { switch (member.type()) { case osmium::item_type::node: if (!get(osmium::item_type::node, member.ref())) { ++m_missing_nodes_in_relations; set(osmium::item_type::node, member.ref()); if (m_show_ids) { std::cout << "n" << member.ref() << " in r" << relation.id() << "\n"; } } break; case osmium::item_type::way: if (!get(osmium::item_type::way, member.ref())) { ++m_missing_ways_in_relations; set(osmium::item_type::way, member.ref()); if (m_show_ids) { std::cout << "w" << member.ref() << " in r" << relation.id() << "\n"; } } break; case osmium::item_type::relation: if (member.ref() > relation.id() || !get(osmium::item_type::relation, member.ref())) { m_relation_refs.emplace_back(member.ref(), relation.id()); } break; default: break; } } } } void show_missing_relation_ids() { for (const auto& refs : m_relation_refs) { std::cout << "r" << refs.first << " in r" << refs.second << "\n"; } } std::size_t used_memory() const noexcept { return m_idset_pos(osmium::item_type::node).used_memory() + m_idset_pos(osmium::item_type::way).used_memory() + m_idset_pos(osmium::item_type::relation).used_memory() + m_idset_neg(osmium::item_type::node).used_memory() + m_idset_neg(osmium::item_type::way).used_memory() + m_idset_neg(osmium::item_type::relation).used_memory() + m_relation_refs.capacity() * sizeof(decltype(m_relation_refs)::value_type); } }; // class RefCheckHandler bool CommandCheckRefs::run() { osmium::io::Reader reader{m_input_file}; osmium::ProgressBar progress_bar{reader.file_size(), display_progress()}; RefCheckHandler handler{m_vout, progress_bar, m_show_ids, m_check_relations}; while (osmium::memory::Buffer buffer = reader.read()) { progress_bar.update(reader.offset()); osmium::apply(buffer, handler); } progress_bar.done(); reader.close(); if (m_check_relations) { handler.find_missing_relations(); if (m_show_ids) { handler.show_missing_relation_ids(); } } std::cerr << "There are " << handler.node_count() << " nodes, " << handler.way_count() << " ways, and " << handler.relation_count() << " relations in this file.\n"; if (m_check_relations) { std::cerr << "Nodes in ways missing: " << handler.missing_nodes_in_ways() << "\n"; std::cerr << "Nodes in relations missing: " << handler.missing_nodes_in_relations() << "\n"; std::cerr << "Ways in relations missing: " << handler.missing_ways_in_relations() << "\n"; std::cerr << "Relations in relations missing: " << handler.missing_relations_in_relations() << "\n"; } else { std::cerr << "Nodes in ways missing: " << handler.missing_nodes_in_ways() << "\n"; } m_vout << "Memory used for indexes: " << (handler.used_memory() / (1024 * 1024)) << " MBytes\n"; show_memory_used(); m_vout << "Done.\n"; return handler.no_errors(); } osmium-tool-1.7.1/src/command_check_refs.hpp000066400000000000000000000027701315004223400210760ustar00rootroot00000000000000#ifndef COMMAND_CHECK_REFS_HPP #define COMMAND_CHECK_REFS_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "cmd.hpp" // IWYU pragma: export class CommandCheckRefs : public Command, public with_single_osm_input { bool m_show_ids = false; bool m_check_relations = false; public: CommandCheckRefs() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "check-refs"; } const char* synopsis() const noexcept override final { return "osmium check-refs [OPTIONS] OSM-DATA-FILE"; } }; // class CommandCheckRefs #endif // COMMAND_CHECK_REFS_HPP osmium-tool-1.7.1/src/command_derive_changes.cpp000066400000000000000000000130451315004223400217400ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_derive_changes.hpp" #include "exception.hpp" #include "util.hpp" bool CommandDeriveChanges::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("increment-version", "Increment version of deleted objects") ("keep-details", "Keep tags (and nodes of ways, members of relations) of deleted objects") ("update-timestamp", "Set timestamp of deleted objects to current time") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_multiple_inputs_options()}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("input-filenames", po::value>(), "Input files") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filenames", -1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_input_files(vm); setup_output_file(vm); if (m_input_files.size() != 2) { throw argument_error{"You need exactly two input files for this command."}; } if (vm.count("increment-version")) { m_increment_version = true; } if (vm.count("keep-details")) { m_keep_details = true; } if (vm.count("update-timestamp")) { m_update_timestamp = true; } return true; } void CommandDeriveChanges::show_arguments() { show_multiple_inputs_arguments(m_vout); show_output_arguments(m_vout); m_vout << " other options:\n"; m_vout << " on deleted objects:\n"; m_vout << " increment version: " << yes_no(m_increment_version); m_vout << " keep details: " << yes_no(m_keep_details); m_vout << " update timestamp: " << yes_no(m_update_timestamp); } void CommandDeriveChanges::write_deleted(osmium::io::Writer& writer, osmium::OSMObject& object) { if (m_increment_version) { object.set_version(object.version() + 1); } if (m_update_timestamp) { object.set_timestamp(std::time(nullptr)); } if (m_keep_details) { object.set_visible(false); writer(object); } else { using namespace osmium::builder::attr; osmium::builder::add_node(m_buffer, _deleted(), _id(object.id()), _version(object.version()), _timestamp(object.timestamp()) ); writer(m_buffer.get(0)); m_buffer.clear(); } } bool CommandDeriveChanges::run() { m_vout << "Opening input files...\n"; osmium::io::Reader reader1{m_input_files[0], osmium::osm_entity_bits::object}; osmium::io::Reader reader2{m_input_files[1], osmium::osm_entity_bits::object}; auto in1 = osmium::io::make_input_iterator_range(reader1); auto in2 = osmium::io::make_input_iterator_range(reader2); auto it1 = in1.begin(); auto it2 = in2.begin(); auto end1 = in1.end(); auto end2 = in2.end(); m_vout << "Opening output file...\n"; if (m_output_file.format() != osmium::io::file_format::xml || !m_output_file.is_true("xml_change_format")) { warning("Output format chosen is not the XML change format. Use .osc(.gz|bz2) as suffix or -f option.\n"); } osmium::io::Header header; setup_header(header); osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; m_vout << "Deriving changes...\n"; while (it1 != end1 || it2 != end2) { if (it2 == end2) { write_deleted(writer, *it1); ++it1; } else if (it1 == end1 || *it2 < *it1) { writer(*it2); ++it2; } else if (*it1 < *it2) { if (it2->id() != it1->id()) { write_deleted(writer, *it1); } ++it1; } else { /* *it1 == *it2 */ ++it1; ++it2; } } writer.close(); reader2.close(); reader1.close(); show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_derive_changes.hpp000066400000000000000000000034041315004223400217430ustar00rootroot00000000000000#ifndef COMMAND_DERIVE_CHANGES_HPP #define COMMAND_DERIVE_CHANGES_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "cmd.hpp" // IWYU pragma: export class CommandDeriveChanges : public Command, public with_multiple_osm_inputs, public with_osm_output { osmium::memory::Buffer m_buffer{128}; bool m_keep_details = false; bool m_update_timestamp = false; bool m_increment_version = false; public: CommandDeriveChanges() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; void write_deleted(osmium::io::Writer& writer, osmium::OSMObject& object); bool run() override final; const char* name() const noexcept override final { return "derive-changes"; } const char* synopsis() const noexcept override final { return "osmium derive-changes [OPTIONS] OSM-FILE1 OSM-FILE2"; } }; // class CommandDeriveChanges #endif // COMMAND_DERIVE_CHANGES_HPP osmium-tool-1.7.1/src/command_diff.cpp000066400000000000000000000240651315004223400177060ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_diff.hpp" #include "exception.hpp" #include "util.hpp" bool CommandDiff::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("object-type,t", po::value>(), "Read only objects of given type (node, way, relation)") ("output,o", po::value(), "Output file") ("output-format,f", po::value(), "Format of output file") ("overwrite,O", "Allow existing output file to be overwritten") ("quiet,q", "Report only when files differ") ("summary,s", "Show summary on STDERR") ("suppress-common,c", "Suppress common objects") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_multiple_inputs_options()}; po::options_description hidden; hidden.add_options() ("input-filenames", po::value>(), "Input files") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filenames", -1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_object_type_nwr(vm); setup_input_files(vm); if (m_input_files.size() != 2) { throw argument_error("You need exactly two input files for this command."); } if (vm.count("output")) { m_output_filename = vm["output"].as(); } if (vm.count("output-format")) { m_output_format = vm["output-format"].as(); } if (vm.count("overwrite")) { m_output_overwrite = osmium::io::overwrite::allow; } if (vm.count("summary")) { m_show_summary = true; } if (vm.count("quiet")) { if (vm.count("output") || vm.count("output-format") || vm.count("overwrite") || vm.count("suppress-common")) { throw argument_error("Do not use --quiet/-q with any of the output options."); } m_output_action = "none"; m_output_format = "no output"; } if (m_output_format == "compact") { m_output_action = "compact"; } if (m_output_action.empty()) { if (m_output_format == "" && (m_output_filename == "" || m_output_filename == "-")) { m_output_format = "compact"; m_output_action = "compact"; } else { m_output_action = "osm"; m_output_file = osmium::io::File(m_output_filename, m_output_format); m_output_file.check(); auto f = m_output_file.format(); if (f != osmium::io::file_format::opl && f != osmium::io::file_format::debug) { throw argument_error("File format does not support diff output. Use 'compact', 'opl' or 'debug' format."); } } } if (vm.count("suppress-common")) { m_suppress_common = true; } return true; } void CommandDiff::show_arguments() { show_multiple_inputs_arguments(m_vout); show_output_arguments(m_vout); m_vout << " other options:\n"; m_vout << " show summary: " << yes_no(m_show_summary); m_vout << " suppress common objects: " << yes_no(m_suppress_common); show_object_types(m_vout); } class OutputAction { public: virtual ~OutputAction() { } virtual void left(osmium::OSMObject& /* object */) { } virtual void right(osmium::OSMObject& /* object */) { } virtual void same(osmium::OSMObject& /* object */) { } virtual void different(osmium::OSMObject& /* left */, osmium::OSMObject& /* right */) { } }; // class OutputAction class OutputActionCompact : public OutputAction { int m_fd; void print(const char diff, const osmium::OSMObject& object) const { std::stringstream ss; ss << diff << osmium::item_type_to_char(object.type()) << object.id() << " v" << object.version() << '\n'; osmium::io::detail::reliable_write(m_fd, ss.str().c_str(), ss.str().size()); } public: explicit OutputActionCompact(int fd) noexcept : m_fd(fd) { } void left(osmium::OSMObject& object) override { print('-', object); } void right(osmium::OSMObject& object) override { print('+', object); } void same(osmium::OSMObject& object) override { print(' ', object); } void different(osmium::OSMObject& left, osmium::OSMObject& /* right */) override { print('*', left); } }; // class OutputActionCompact class OutputActionOSM : public OutputAction { osmium::io::Writer m_writer; public: OutputActionOSM(const osmium::io::File& file, osmium::io::overwrite ow) : m_writer(file, ow) { } void left(osmium::OSMObject& object) override { m_writer(object); } void right(osmium::OSMObject& object) override { m_writer(object); } void same(osmium::OSMObject& object) override { m_writer(object); } void different(osmium::OSMObject& left, osmium::OSMObject& right) override { m_writer(left); m_writer(right); } }; // class OutputActionOSM bool CommandDiff::run() { osmium::io::Reader reader1{m_input_files[0], osm_entity_bits()}; osmium::io::Reader reader2{m_input_files[1], osm_entity_bits()}; auto in1 = osmium::io::make_input_iterator_range(reader1); auto in2 = osmium::io::make_input_iterator_range(reader2); auto it1 = in1.begin(); auto it2 = in2.begin(); auto end1 = in1.end(); auto end2 = in2.end(); std::unique_ptr action; if (m_output_action == "compact") { const int fd = osmium::io::detail::open_for_writing(m_output_filename, m_output_overwrite); action.reset(new OutputActionCompact{fd}); } else if (m_output_action == "osm") { m_output_file.set("diff"); action.reset(new OutputActionOSM{m_output_file, m_output_overwrite}); } uint64_t count_left = 0; uint64_t count_right = 0; uint64_t count_same = 0; uint64_t count_different = 0; while (it1 != end1 || it2 != end2) { if (it1 == end1 || *it2 < *it1) { it2->set_diff(osmium::diff_indicator_type::right); ++count_right; if (action) { action->right(*it2); } ++it2; } else if (it2 == end2 || *it1 < *it2) { it1->set_diff(osmium::diff_indicator_type::left); ++count_left; if (action) { action->left(*it1); } ++it1; } else { /* *it1 == *it2 */ osmium::CRC crc1; osmium::CRC crc2; switch (it1->type()) { case osmium::item_type::node: crc1.update(static_cast(*it1)); crc2.update(static_cast(*it2)); break; case osmium::item_type::way: crc1.update(static_cast(*it1)); crc2.update(static_cast(*it2)); break; case osmium::item_type::relation: crc1.update(static_cast(*it1)); crc2.update(static_cast(*it2)); break; default: break; } if (crc1().checksum() == crc2().checksum()) { ++count_same; if (!m_suppress_common) { it1->set_diff(osmium::diff_indicator_type::both); it2->set_diff(osmium::diff_indicator_type::both); if (action) { action->same(*it1); } } } else { ++count_different; it1->set_diff(osmium::diff_indicator_type::left); it2->set_diff(osmium::diff_indicator_type::right); if (action) { action->different(*it1, *it2); } } ++it1; ++it2; } } if (m_show_summary) { std::cerr << "Summary: left=" << count_left << " right=" << count_right << " same=" << count_same << " different=" << count_different << "\n"; } show_memory_used(); m_vout << "Done.\n"; return count_left == 0 && count_right == 0 && count_different == 0; } osmium-tool-1.7.1/src/command_diff.hpp000066400000000000000000000030201315004223400176770ustar00rootroot00000000000000#ifndef COMMAND_DIFF_HPP #define COMMAND_DIFF_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "cmd.hpp" // IWYU pragma: export class CommandDiff : public Command, public with_multiple_osm_inputs, public with_osm_output { std::string m_output_action; bool m_show_summary = false; bool m_suppress_common = false; public: CommandDiff() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "diff"; } const char* synopsis() const noexcept override final { return "osmium diff [OPTIONS] OSM-FILE1 OSM-FILE2"; } }; // class CommandDiff #endif // COMMAND_DIFF_HPP osmium-tool-1.7.1/src/command_export.cpp000066400000000000000000000363651315004223400203250ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_export.hpp" #include "exception.hpp" #include "util.hpp" #include "export/export_handler.hpp" #include "export/export_format_json.hpp" #include "export/export_format_text.hpp" static std::string get_attr_string(const rapidjson::Value& object, const char* key) { const auto it = object.FindMember(key); if (it == object.MemberEnd()) { return ""; } if (it->value.IsString()) { return it->value.GetString(); } if (it->value.IsBool()) { if (it->value.GetBool()) { return std::string{"@"} + key; } } return ""; } void CommandExport::parse_options(const rapidjson::Value& attributes) { if (!attributes.IsObject()) { throw config_error{"'attributes' member must be an object."}; } m_options.type = get_attr_string(attributes, "type"); m_options.id = get_attr_string(attributes, "id"); m_options.version = get_attr_string(attributes, "version"); m_options.changeset = get_attr_string(attributes, "changeset"); m_options.timestamp = get_attr_string(attributes, "timestamp"); m_options.uid = get_attr_string(attributes, "uid"); m_options.user = get_attr_string(attributes, "user"); m_options.way_nodes = get_attr_string(attributes, "way_nodes"); } static bool parse_string_array(const rapidjson::Value& object, const char* key, std::vector& result) { const auto json = object.FindMember(key); if (json == object.MemberEnd()) { return false; } if (!json->value.IsArray()) { throw config_error{std::string{"'"} + key + "' member in top-level object must be array."}; } for (const auto& value : json->value.GetArray()) { if (!value.IsString()) { throw config_error{std::string{"Array elements in '"} + key + "' must be strings."}; } if (value.GetString()[0] != '\0') { result.emplace_back(value.GetString()); } } return true; } void CommandExport::parse_config_file() { std::ifstream config_file{m_config_file_name}; rapidjson::IStreamWrapper stream_wrapper{config_file}; rapidjson::Document doc; if (doc.ParseStream<(rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag)>(stream_wrapper).HasParseError()) { throw config_error{std::string{"JSON error at offset "} + std::to_string(doc.GetErrorOffset()) + ": " + rapidjson::GetParseError_En(doc.GetParseError()) }; } if (!doc.IsObject()) { throw config_error{"Top-level value must be an object."}; } const auto json_attr = doc.FindMember("attributes"); if (json_attr != doc.MemberEnd()) { parse_options(json_attr->value); } parse_string_array(doc, "linear_tags", m_linear_tags); parse_string_array(doc, "area_tags", m_area_tags); parse_string_array(doc, "include_tags", m_include_tags); parse_string_array(doc, "exclude_tags", m_exclude_tags); } void CommandExport::canonicalize_output_format() { for (auto& c : m_output_format) { c = std::tolower(c); } if (m_output_format == "json") { m_output_format = "geojson"; return; } if (m_output_format == "jsonseq") { m_output_format = "geojsonseq"; return; } if (m_output_format == "txt") { m_output_format = "text"; return; } } bool CommandExport::setup(const std::vector& arguments) { const auto& map_factory = osmium::index::MapFactory::instance(); std::string default_index_type{"flex_mem"}; po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("add-unique-id,u", po::value(), "Add unique id to each feature ('counter' or 'type_id')") ("config,c", po::value(), "Config file") ("fsync", "Call fsync after writing file") ("index-type,i", po::value()->default_value(default_index_type), "Index type to use") ("keep-untagged,n", "Keep features that don't have any tags") ("output,o", po::value(), "Output file (default: STDOUT)") ("output-format,f", po::value(), "Output format (default depends on output file suffix)") ("overwrite,O", "Allow existing output file to be overwritten") ("show-errors,e", "Output any geometry errors on STDOUT") ("stop-on-error,E", "Stop on the first error encountered") ("show-index-types,I", "Show available index types") ("omit-rs,r", "Do not print RS (record separator) character when using JSON Text Sequences") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_single_input_options()}; po::options_description hidden; hidden.add_options() ("input-filename", po::value(), "OSM input file") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filename", 1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); if (vm.count("show-index-types")) { for (const auto& map_type : map_factory.map_types()) { std::cout << map_type << '\n'; } std::cout << "none\n"; return false; } setup_common(vm, desc); setup_input_file(vm); if (vm.count("config")) { m_config_file_name = vm["config"].as(); try { parse_config_file(); } catch (const config_error&) { std::cerr << "Error while reading config file '" << m_config_file_name << "':\n"; throw; } } if (vm.count("add-unique-id")) { const std::string value = vm["add-unique-id"].as(); if (value == "counter") { m_options.unique_id = unique_id_type::counter; } else if (value == "type_id") { m_options.unique_id = unique_id_type::type_id; } else { throw argument_error{"Unknown --add-unique-id, -u setting. Use 'counter' or 'type_id'."}; } } if (vm.count("fsync")) { m_fsync = osmium::io::fsync::yes; } if (vm.count("index-type")) { m_index_type_name = vm["index-type"].as(); if (m_index_type_name != "none" && !map_factory.has_map_type(m_index_type_name)) { throw argument_error{std::string{"Unknown index type '"} + m_index_type_name + "'. Use --show-index-types or -I to get a list."}; } } if (vm.count("keep-untagged")) { m_options.keep_untagged = true; } if (vm.count("output")) { m_output_filename = vm["output"].as(); const auto pos = m_output_filename.rfind('.'); if (pos != std::string::npos) { m_output_format = m_output_filename.substr(pos + 1); } } else { m_output_filename = "-"; } if (vm.count("output-format")) { m_output_format = vm["output-format"].as(); } canonicalize_output_format(); if (m_output_format != "geojson" && m_output_format != "geojsonseq" && m_output_format != "text") { throw argument_error{"Set output format with --output-format or -f to 'geojson', 'geojsonseq', or 'text'."}; } if (vm.count("overwrite")) { m_output_overwrite = osmium::io::overwrite::allow; } if (vm.count("omit-rs")) { m_options.print_record_separator = false; if (m_output_format != "geojsonseq") { warning("The --omit-rs/-r option only works for GeoJSON Text Sequence (geojsonseq) format. Ignored.\n"); } } if (vm.count("show-errors")) { m_show_errors = true; } if (vm.count("stop-on-error")) { m_show_errors = true; m_stop_on_error = true; } if (!m_include_tags.empty() && !m_exclude_tags.empty()) { throw config_error{"Setting both 'include_tags' and 'exclude_tags' is not allowed."}; } if (!m_include_tags.empty()) { initialize_tags_filter(m_options.tags_filter, false, m_include_tags); } else if (!m_exclude_tags.empty()) { initialize_tags_filter(m_options.tags_filter, true, m_exclude_tags); } return true; } static void print_taglist(osmium::util::VerboseOutput& vout, const std::vector& strings) { for (const auto& str : strings) { vout << " " << str << '\n'; } } static const char* print_unique_id_type(unique_id_type unique_id) { switch (unique_id) { case unique_id_type::counter: return "counter"; case unique_id_type::type_id: return "type and id"; default: break; } return "no"; } void CommandExport::show_arguments() { show_single_input_arguments(m_vout); m_vout << " output options:\n"; m_vout << " file name: " << m_output_filename << '\n'; if (m_output_format == "geojsonseq") { m_vout << " file format: geojsonseq (with" << (m_options.print_record_separator ? " RS)\n" : "out RS)\n"); } else { m_vout << " file format: " << m_output_format << '\n'; } m_vout << " overwrite: " << yes_no(m_output_overwrite == osmium::io::overwrite::allow); m_vout << " fsync: " << yes_no(m_fsync == osmium::io::fsync::yes); m_vout << " attributes:\n"; m_vout << " type: " << (m_options.type.empty() ? "(omitted)" : m_options.type) << '\n'; m_vout << " id: " << (m_options.id.empty() ? "(omitted)" : m_options.id) << '\n'; m_vout << " version: " << (m_options.version.empty() ? "(omitted)" : m_options.version) << '\n'; m_vout << " changeset: " << (m_options.changeset.empty() ? "(omitted)" : m_options.changeset) << '\n'; m_vout << " timestamp: " << (m_options.timestamp.empty() ? "(omitted)" : m_options.timestamp) << '\n'; m_vout << " uid: " << (m_options.uid.empty() ? "(omitted)" : m_options.uid) << '\n'; m_vout << " user: " << (m_options.user.empty() ? "(omitted)" : m_options.user) << '\n'; m_vout << " way_nodes: " << (m_options.way_nodes.empty() ? "(omitted)" : m_options.way_nodes) << '\n'; m_vout << " linear tags:\n"; print_taglist(m_vout, m_linear_tags); m_vout << " area tags:\n"; print_taglist(m_vout, m_area_tags); if (!m_include_tags.empty()) { m_vout << " include only these tags:\n"; print_taglist(m_vout, m_include_tags); } else if (!m_exclude_tags.empty()) { m_vout << " exclude these tags:\n"; print_taglist(m_vout, m_exclude_tags); } m_vout << " other options:\n"; m_vout << " index type: " << m_index_type_name << '\n'; m_vout << " add unique IDs: " << print_unique_id_type(m_options.unique_id) << '\n'; m_vout << " keep untagged features: " << yes_no(m_options.keep_untagged); } static std::unique_ptr create_handler(const std::string& output_format, const std::string& output_filename, osmium::io::overwrite overwrite, osmium::io::fsync fsync, const options_type& options) { if (output_format == "geojson" || output_format == "geojsonseq") { return std::unique_ptr{new ExportFormatJSON{output_format, output_filename, overwrite, fsync, options}}; } if (output_format == "text") { return std::unique_ptr{new ExportFormatText{output_format, output_filename, overwrite, fsync, options}}; } throw argument_error{"Unknown output format"}; } bool CommandExport::run() { osmium::area::Assembler::config_type assembler_config; osmium::area::MultipolygonManager mp_manager{assembler_config}; m_vout << "First pass through input file (reading relations)...\n"; osmium::relations::read_relations(m_input_file, mp_manager); m_vout << "First pass done.\n"; m_vout << "Second pass through input file...\n"; auto handler = create_handler(m_output_format, m_output_filename, m_output_overwrite, m_fsync, m_options); ExportHandler export_handler{std::move(handler), m_linear_tags, m_area_tags, m_show_errors, m_stop_on_error}; osmium::handler::CheckOrder check_order_handler; if (m_index_type_name == "none") { osmium::io::Reader reader{m_input_file}; osmium::apply(reader, check_order_handler, export_handler, mp_manager.handler([&export_handler](osmium::memory::Buffer&& buffer) { osmium::apply(buffer, export_handler); })); reader.close(); } else { const auto& map_factory = osmium::index::MapFactory::instance(); auto location_index = map_factory.create_map(m_index_type_name); location_handler_type location_handler{*location_index}; location_handler.ignore_errors(); osmium::io::Reader reader{m_input_filename}; osmium::apply(reader, check_order_handler, location_handler, export_handler, mp_manager.handler([&export_handler](osmium::memory::Buffer&& buffer) { osmium::apply(buffer, export_handler); })); reader.close(); m_vout << "About " << (location_index->used_memory() / (1024 * 1024)) << " MBytes used for node location index (in main memory or on disk).\n"; } m_vout << "Second pass done.\n"; export_handler.close(); m_vout << "Wrote " << export_handler.count() << " features.\n"; m_vout << "Encountered " << export_handler.error_count() << " errors.\n"; show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_export.hpp000066400000000000000000000046611315004223400203240ustar00rootroot00000000000000#ifndef COMMAND_EXPORT_HPP #define COMMAND_EXPORT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include "cmd.hpp" // IWYU pragma: export #include "export/options.hpp" class CommandExport : public Command, public with_single_osm_input { using index_type = osmium::index::map::Map; using location_handler_type = osmium::handler::NodeLocationsForWays; options_type m_options; std::vector m_linear_tags; std::vector m_area_tags; std::vector m_include_tags; std::vector m_exclude_tags; std::string m_config_file_name; std::string m_index_type_name; std::string m_output_filename; std::string m_output_format; osmium::io::overwrite m_output_overwrite = osmium::io::overwrite::no; osmium::io::fsync m_fsync = osmium::io::fsync::no; bool m_show_errors = false; bool m_stop_on_error = false; void canonicalize_output_format(); void parse_options(const rapidjson::Value& attributes); void parse_config_file(); public: CommandExport() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "export"; } const char* synopsis() const noexcept override final { return "osmium export [OPTIONS] OSM-FILE"; } }; // class CommandExport #endif // COMMAND_EXPORT_HPP osmium-tool-1.7.1/src/command_extract.cpp000066400000000000000000000503771315004223400204550ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_extract.hpp" #include "exception.hpp" #include "extract/extract_bbox.hpp" #include "extract/extract_polygon.hpp" #include "extract/geojson_file_parser.hpp" #include "extract/osm_file_parser.hpp" #include "extract/poly_file_parser.hpp" #include "extract/strategy_complete_ways.hpp" #include "extract/strategy_complete_ways_with_history.hpp" #include "extract/strategy_simple.hpp" #include "extract/strategy_smart.hpp" #include "util.hpp" namespace { osmium::Box parse_bbox(const rapidjson::Value& value) { if (value.IsArray()) { if (value.Size() == 4) { if (value[0].IsNumber() && value[1].IsNumber() && value[2].IsNumber() && value[3].IsNumber()) { const osmium::Location bottom_left{value[0].GetDouble(), value[1].GetDouble()}; const osmium::Location top_right{value[2].GetDouble(), value[3].GetDouble()}; if (bottom_left < top_right) { return osmium::Box{bottom_left, top_right}; } throw config_error{"'bbox' array elements must be in order: left, bottom, right, top."}; } throw config_error{"'bbox' array elements must be numbers."}; } else { throw config_error{"'bbox' must be an array with exactly four elements."}; } } else if (value.IsObject()) { const auto left = value.FindMember("left"); const auto right = value.FindMember("right"); const auto top = value.FindMember("top"); const auto bottom = value.FindMember("bottom"); if (left != value.MemberEnd() && right != value.MemberEnd() && top != value.MemberEnd() && bottom != value.MemberEnd()) { if (left->value.IsNumber() && right->value.IsNumber() && top->value.IsNumber() && bottom->value.IsNumber()) { const osmium::Location bottom_left{left->value.GetDouble(), bottom->value.GetDouble()}; const osmium::Location top_right{right->value.GetDouble(), top->value.GetDouble()}; if (bottom_left.x() < top_right.x() && bottom_left.y() < top_right.y()) { return osmium::Box{bottom_left, top_right}; } throw config_error{"Need 'left' < 'right' and 'bottom' < 'top' in 'bbox' object."}; } throw config_error{"Members in 'bbox' object must be numbers."}; } throw config_error{"Need 'left', 'right', 'top', and 'bottom' members in 'bbox' object."}; } throw config_error{"'bbox' member is not an array or object."}; } std::size_t parse_multipolygon_object(const std::string& directory, std::string file_name, std::string file_type, osmium::memory::Buffer& buffer) { if (file_name.empty()) { throw config_error{"Missing 'file_name' in '(multi)polygon' object."}; } if (file_name[0] != '/') { // relative file name file_name = directory + file_name; } // If the file type is not set, try to deduce it from the file name // suffix. if (file_type.empty()) { std::string suffix{get_filename_suffix(file_name)}; if (suffix == "poly") { file_type = "poly"; } else if (suffix == "json" || suffix == "geojson") { file_type = "geojson"; } else { osmium::io::File osmfile{"", suffix}; if (osmfile.format() != osmium::io::file_format::unknown) { file_type = "osm"; } } } if (file_type == "osm") { try { OSMFileParser parser{buffer, file_name}; return parser(); } catch (const std::system_error& e) { throw osmium::io_error{std::string{"While reading file '"} + file_name + "':\n" + e.what()}; } catch (const osmium::io_error& e) { throw osmium::io_error{std::string{"While reading file '"} + file_name + "':\n" + e.what()}; } catch (const osmium::out_of_order_error& e) { throw osmium::io_error{std::string{"While reading file '"} + file_name + "':\n" + e.what()}; } } else if (file_type == "geojson") { GeoJSONFileParser parser{buffer, file_name}; try { return parser(); } catch (const config_error& e) { throw geojson_error{e.what()}; } } else if (file_type == "poly") { PolyFileParser parser{buffer, file_name}; return parser(); } else if (file_type == "") { throw config_error{"Could not autodetect file type in '(multi)polygon' object. Add a 'file_type'."}; } throw config_error{std::string{"Unknown file type: '"} + file_type + "' in '(multi)polygon.file_type'"}; } std::size_t parse_multipolygon_object(const std::string& directory, const rapidjson::Value& value, osmium::memory::Buffer& buffer) { std::string file_name{get_value_as_string(value, "file_name")}; std::string file_type{get_value_as_string(value, "file_type")}; return parse_multipolygon_object(directory, file_name, file_type, buffer); } std::size_t parse_polygon(const std::string& directory, const rapidjson::Value& value, osmium::memory::Buffer& buffer) { if (value.IsArray()) { return parse_polygon_array(value, buffer); } else if (value.IsObject()) { return parse_multipolygon_object(directory, value, buffer); } throw config_error{"Polygon must be an object or array."}; } std::size_t parse_multipolygon(const std::string& directory, const rapidjson::Value& value, osmium::memory::Buffer& buffer) { if (value.IsArray()) { return parse_multipolygon_array(value, buffer); } else if (value.IsObject()) { return parse_multipolygon_object(directory, value, buffer); } throw config_error{"Multipolygon must be an object or array."}; } } // anonymous namespace void CommandExtract::set_directory(const std::string& directory) { m_output_directory = directory; if (m_output_directory.empty() || m_output_directory.back() != '/') { m_output_directory += '/'; } } void CommandExtract::parse_config_file() { std::ifstream config_file{m_config_file_name}; rapidjson::IStreamWrapper stream_wrapper{config_file}; rapidjson::Document doc; if (doc.ParseStream<(rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag)>(stream_wrapper).HasParseError()) { throw config_error{std::string{"JSON error at offset "} + std::to_string(doc.GetErrorOffset()) + ": " + rapidjson::GetParseError_En(doc.GetParseError()) }; } if (!doc.IsObject()) { throw config_error{"Top-level value must be an object."}; } std::string directory{get_value_as_string(doc, "directory")}; if (!directory.empty() && m_output_directory.empty()) { m_vout << " Directory set to '" << directory << "'.\n"; set_directory(directory); } const auto json_extracts = doc.FindMember("extracts"); if (json_extracts == doc.MemberEnd()) { throw config_error{"Missing 'extracts' member in top-level object."}; } if (!json_extracts->value.IsArray()) { throw config_error{"'extracts' member in top-level object must be array."}; } m_vout << " Reading extracts from config file...\n"; int extract_num = 1; for (const auto& e : json_extracts->value.GetArray()) { std::string output; try { if (!e.IsObject()) { throw config_error{"Members in 'extracts' array must be objects."}; } output = get_value_as_string(e, "output"); if (output.empty()) { throw config_error{"Missing 'output' field for extract."}; } m_vout << " Looking at extract '" << output << "'...\n"; std::string output_format{get_value_as_string(e, "output_format")}; std::string description{get_value_as_string(e, "description")}; const auto json_bbox = e.FindMember("bbox"); const auto json_polygon = e.FindMember("polygon"); const auto json_multipolygon = e.FindMember("multipolygon"); osmium::io::File output_file{m_output_directory + output, output_format}; if (m_with_history) { output_file.set_has_multiple_object_versions(true); } else if (output_file.has_multiple_object_versions()) { throw config_error{"Looks like you are trying to write a history file, but option --with-history is not set."}; } if (json_bbox != e.MemberEnd()) { m_extracts.emplace_back(new ExtractBBox{output_file, description, parse_bbox(json_bbox->value)}); } else if (json_polygon != e.MemberEnd()) { m_extracts.emplace_back(new ExtractPolygon{output_file, description, m_buffer, parse_polygon(m_config_directory, json_polygon->value, m_buffer)}); } else if (json_multipolygon != e.MemberEnd()) { m_extracts.emplace_back(new ExtractPolygon{output_file, description, m_buffer, parse_multipolygon(m_config_directory, json_multipolygon->value, m_buffer)}); } else { throw config_error{"Missing geometry for extract. Need 'bbox', 'polygon', or 'multipolygon'."}; } Extract& extract = *m_extracts.back(); const auto json_output_header = e.FindMember("output_header"); if (json_output_header != e.MemberEnd()) { const auto& value = json_output_header->value; if (!value.IsObject()) { throw config_error{"Optional 'output_header' field must be an object."}; } for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it) { const auto& member_value = it->value; if (!member_value.IsString()) { throw config_error{"Values in 'output_header' object must be strings."}; } extract.add_header_option(it->name.GetString(), member_value.GetString()); } } } catch (const config_error& e) { std::string message{"In extract "}; message += std::to_string(extract_num); message += ": "; message += e.what(); throw config_error{message}; } catch (const poly_error&) { std::cerr << "Error while reading poly file for extract " << extract_num << " (" << output << "):\n"; throw; } catch (const geojson_error&) { std::cerr << "Error while reading GeoJSON file for extract " << extract_num << " (" << output << "):\n"; throw; } catch (const std::system_error&) { std::cerr << "Error while reading OSM file for extract " << extract_num << " (" << output << "):\n"; throw; } catch (const osmium::io_error&) { std::cerr << "Error while reading OSM file for extract " << extract_num << " (" << output << "):\n"; throw; } catch (const osmium::out_of_order_error&) { std::cerr << "Error while reading OSM file for extract " << extract_num << " (" << output << "):\n"; throw; } ++extract_num; } m_vout << '\n'; } std::unique_ptr CommandExtract::make_strategy(const std::string& name) { if (name == "simple") { if (m_with_history) { throw argument_error{"The 'simple' strategy is not supported for history files."}; } else { return std::unique_ptr(new strategy_simple::Strategy{m_extracts, m_options}); } } else if (name == "complete_ways") { if (m_with_history) { return std::unique_ptr(new strategy_complete_ways_with_history::Strategy{m_extracts, m_options}); } else { return std::unique_ptr(new strategy_complete_ways::Strategy{m_extracts, m_options}); } } else if (name == "smart") { if (m_with_history) { throw argument_error{"The 'smart' strategy is not supported for history files."}; } else { return std::unique_ptr(new strategy_smart::Strategy{m_extracts, m_options}); } } throw argument_error{std::string{"Unknown extract strategy: '"} + name + "'."}; } bool CommandExtract::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("bbox,b", po::value(), "Bounding box") ("config,c", po::value(), "Config file") ("directory,d", po::value(), "Output directory (default: from config)") ("option,S", po::value>(), "Set strategy option") ("polygon,p", po::value(), "Polygon file") ("strategy,s", po::value()->default_value("complete_ways"), "Use named extract strategy") ("with-history,H", "Input file and output files are history files") ("set-bounds", "Sets bounds (bounding box) in header") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_single_input_options()}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("input-filename", po::value(), "OSM input file") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filename", 1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_progress(vm); setup_input_file(vm); init_output_file(vm); if (vm.count("config") + vm.count("bbox") + vm.count("polygon") > 1) { throw argument_error{"Can only use one of --config/-c, --bbox/-b, or --polygon/-p."}; } if (vm.count("with-history")) { m_with_history = true; } if (vm.count("config")) { if (vm.count("directory")) { set_directory(vm["directory"].as()); } if (vm.count("output")) { warning("Ignoring --output/-o option.\n"); } if (vm.count("output-format")) { warning("Ignoring --output-format/-f option.\n"); } m_config_file_name = vm["config"].as(); auto slash = m_config_file_name.find_last_of('/'); if (slash != std::string::npos) { m_config_directory = m_config_file_name; m_config_directory.resize(slash + 1); } } if (vm.count("bbox")) { if (vm.count("directory")) { warning("Ignoring --directory/-d option.\n"); } check_output_file(); m_extracts.emplace_back(new ExtractBBox{m_output_file, "", parse_bbox(vm["bbox"].as(), "--box/-b")}); } if (vm.count("polygon")) { if (vm.count("directory")) { warning("Ignoring --directory/-d option.\n"); } check_output_file(); m_extracts.emplace_back(new ExtractPolygon{m_output_file, "", m_buffer, parse_multipolygon_object("./", vm["polygon"].as(), "", m_buffer)}); } if (vm.count("option")) { for (const auto& option : vm["option"].as>()) { m_options.set(option); } } if (vm.count("set-bounds")) { m_set_bounds = true; } if (vm.count("strategy")) { m_strategy_name = vm["strategy"].as(); } return true; } void CommandExtract::show_arguments() { show_single_input_arguments(m_vout); show_output_arguments(m_vout); m_vout << " strategy options:\n"; m_vout << " strategy: " << m_strategy_name << '\n'; m_vout << " with history: " << yes_no(m_with_history); m_vout << " other options:\n"; m_vout << " config file: " << m_config_file_name << '\n'; m_vout << " output directory: " << m_output_directory << '\n'; m_vout << '\n'; } void CommandExtract::show_extracts() { m_vout << "Extracts:\n"; int n = 1; for (const auto& e : m_extracts) { const char old_fill = std::cerr.fill(); m_vout << "[" << std::setw(2) << std::setfill('0') << n << "] Output: " << e->output() << '\n'; std::cerr.fill(old_fill); m_vout << " Format: " << e->output_format() << '\n'; m_vout << " Description: " << e->description() << '\n'; if (!e->header_options().empty()) { m_vout << " Header opts: "; bool first = true; for (const auto& opt : e->header_options()) { if (first) { first = false; } else { m_vout << " "; } m_vout << opt.first << ": " << opt.second << '\n'; } } m_vout << " Envelope: " << e->envelope_as_text() << '\n'; m_vout << " Type: " << e->geometry_type() << '\n'; m_vout << " Geometry: " << e->geometry_as_text() << '\n'; ++n; } m_vout << '\n'; } bool CommandExtract::run() { if (!m_config_file_name.empty()) { m_vout << "Reading config file...\n"; try { parse_config_file(); } catch (const config_error&) { std::cerr << "Error while reading config file '" << m_config_file_name << "':\n"; throw; } } show_extracts(); m_strategy = make_strategy(m_strategy_name); m_strategy->show_arguments(m_vout); osmium::io::Header header; setup_header(header); for (const auto& extract : m_extracts) { osmium::io::Header file_header{header}; if (m_with_history) { file_header.set_has_multiple_object_versions(true); } if (m_set_bounds) { file_header.add_box(extract->envelope()); } for (const auto& p : extract->header_options()) { file_header.set(p.first, p.second); } extract->open_file(file_header, m_output_overwrite, m_fsync); } m_strategy->run(m_vout, display_progress(), m_input_file); for (const auto& extract : m_extracts) { extract->close_file(); } show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_extract.hpp000066400000000000000000000047321315004223400204540ustar00rootroot00000000000000#ifndef COMMAND_EXTRACT_HPP #define COMMAND_EXTRACT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include "cmd.hpp" // IWYU pragma: export #include "extract/extract.hpp" #include "extract/strategy.hpp" class CommandExtract : public Command, public with_single_osm_input, public with_osm_output { static const std::size_t initial_buffer_size = 10 * 1024; std::string m_config_file_name; std::string m_config_directory; std::string m_output_directory; osmium::util::Options m_options; std::string m_strategy_name; std::unique_ptr m_strategy; std::vector> m_extracts; osmium::memory::Buffer m_buffer{initial_buffer_size, osmium::memory::Buffer::auto_grow::yes}; bool m_with_history = false; bool m_set_bounds = false; void parse_config_file(); void show_extracts(); void set_directory(const std::string& directory); std::unique_ptr make_strategy(const std::string& name); public: CommandExtract() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "extract"; } const char* synopsis() const noexcept override final { return "osmium extract --config CONFIG-FILE [OPTIONS] OSM-FILE\n" " osmium extract --bbox LEFT,BOTTOM,RIGHT,TOP [OPTIONS] OSM-FILE\n" " osmium extract --polygon POLYGON-FILE [OPTIONS] OSM-FILE"; } }; // class CommandExtract #endif // COMMAND_EXTRACT_HPP osmium-tool-1.7.1/src/command_fileinfo.cpp000066400000000000000000000465761315004223400206040ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #ifndef _MSC_VER # include #endif #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #include #include #pragma GCC diagnostic pop #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_fileinfo.hpp" #include "exception.hpp" #include "util.hpp" /*************************************************************************/ struct InfoHandler : public osmium::handler::Handler { osmium::Box bounds; uint64_t changesets = 0; uint64_t nodes = 0; uint64_t ways = 0; uint64_t relations = 0; osmium::max_op largest_changeset_id{0}; osmium::max_op largest_node_id{0}; osmium::max_op largest_way_id{0}; osmium::max_op largest_relation_id{0}; osmium::min_op first_timestamp; osmium::max_op last_timestamp; osmium::CRC crc32; bool ordered = true; bool multiple_versions = false; osmium::item_type last_type = osmium::item_type::undefined; osmium::object_id_type last_id = 0; void changeset(const osmium::Changeset& changeset) { if (last_type == osmium::item_type::changeset) { if (last_id > changeset.id()) { ordered = false; } } else { last_type = osmium::item_type::changeset; } last_id = changeset.id(); crc32.update(changeset); ++changesets; largest_changeset_id.update(changeset.id()); } void osm_object(const osmium::OSMObject& object) { first_timestamp.update(object.timestamp()); last_timestamp.update(object.timestamp()); if (last_type == object.type()) { if (last_id == object.id()) { multiple_versions = true; } if (osmium::id_order{}(object.id(), last_id)) { ordered = false; } } else if (last_type != osmium::item_type::changeset && last_type > object.type()) { ordered = false; } last_type = object.type(); last_id = object.id(); } void node(const osmium::Node& node) { crc32.update(node); bounds.extend(node.location()); ++nodes; largest_node_id.update(node.id()); } void way(const osmium::Way& way) { crc32.update(way); ++ways; largest_way_id.update(way.id()); } void relation(const osmium::Relation& relation) { crc32.update(relation); ++relations; largest_relation_id.update(relation.id()); } }; // struct InfoHandler class Output { public: virtual ~Output() = default; virtual void file(const std::string& filename, const osmium::io::File& input_file) = 0; virtual void header(const osmium::io::Header& header) = 0; virtual void data(const osmium::io::Header& header, const InfoHandler& info_handler) = 0; virtual void output() { } }; // class Output class HumanReadableOutput : public Output { public: void file(const std::string& input_filename, const osmium::io::File& input_file) override final { std::cout << "File:\n"; std::cout << " Name: " << input_filename << "\n"; std::cout << " Format: " << input_file.format() << "\n"; std::cout << " Compression: " << input_file.compression() << "\n"; if (!input_file.filename().empty()) { std::cout << " Size: " << osmium::util::file_size(input_file.filename()) << "\n"; } } void header(const osmium::io::Header& header) override final { std::cout << "Header:\n"; std::cout << " Bounding boxes:\n"; for (const auto& box : header.boxes()) { std::cout << " " << box << "\n"; } std::cout << " With history: " << yes_no(header.has_multiple_object_versions()); std::cout << " Options:\n"; for (const auto& option : header) { std::cout << " " << option.first << "=" << option.second << "\n"; } } void data(const osmium::io::Header& header, const InfoHandler& info_handler) override final { std::cout << "Data:\n"; std::cout << " Bounding box: " << info_handler.bounds << "\n"; if (info_handler.first_timestamp() != osmium::end_of_time()) { std::cout << " Timestamps:\n"; std::cout << " First: " << info_handler.first_timestamp() << "\n"; std::cout << " Last: " << info_handler.last_timestamp() << "\n"; } std::cout << " Objects ordered (by type and id): " << yes_no(info_handler.ordered); std::cout << " Multiple versions of same object: "; if (info_handler.ordered) { std::cout << yes_no(info_handler.multiple_versions); if (info_handler.multiple_versions != header.has_multiple_object_versions()) { std::cout << " WARNING! This is different from the setting in the header.\n"; } } else { std::cout << "unknown (because objects in file are unordered)\n"; } std::cout << " CRC32: " << std::hex << info_handler.crc32().checksum() << std::dec << "\n"; std::cout << " Number of changesets: " << info_handler.changesets << "\n"; std::cout << " Number of nodes: " << info_handler.nodes << "\n"; std::cout << " Number of ways: " << info_handler.ways << "\n"; std::cout << " Number of relations: " << info_handler.relations << "\n"; std::cout << " Largest changeset ID: " << info_handler.largest_changeset_id() << "\n"; std::cout << " Largest node ID: " << info_handler.largest_node_id() << "\n"; std::cout << " Largest way ID: " << info_handler.largest_way_id() << "\n"; std::cout << " Largest relation ID: " << info_handler.largest_relation_id() << "\n"; } }; // class HumanReadableOutput class JSONOutput : public Output { using writer_type = rapidjson::PrettyWriter; rapidjson::StringBuffer m_stream; writer_type m_writer; public: JSONOutput() : m_stream(), m_writer(m_stream) { m_writer.StartObject(); } void file(const std::string& input_filename, const osmium::io::File& input_file) override final { m_writer.String("file"); m_writer.StartObject(); m_writer.String("name"); m_writer.String(input_filename.c_str()); m_writer.String("format"); m_writer.String(osmium::io::as_string(input_file.format())); m_writer.String("compression"); m_writer.String(osmium::io::as_string(input_file.compression())); if (!input_file.filename().empty()) { m_writer.String("size"); m_writer.Int64(osmium::util::file_size(input_file.filename())); } m_writer.EndObject(); } void add_bbox(const osmium::Box& box) { m_writer.StartArray(); m_writer.Double(box.bottom_left().lon()); m_writer.Double(box.bottom_left().lat()); m_writer.Double(box.top_right().lon()); m_writer.Double(box.top_right().lat()); m_writer.EndArray(); } void header(const osmium::io::Header& header) override final { m_writer.String("header"); m_writer.StartObject(); m_writer.String("boxes"); m_writer.StartArray(); for (const auto& box : header.boxes()) { add_bbox(box); } m_writer.EndArray(); m_writer.String("with_history"); m_writer.Bool(header.has_multiple_object_versions()); m_writer.String("option"); m_writer.StartObject(); for (const auto& option : header) { m_writer.String(option.first.c_str()); m_writer.String(option.second.c_str()); } m_writer.EndObject(); m_writer.EndObject(); } void data(const osmium::io::Header& /*header*/, const InfoHandler& info_handler) override final { m_writer.String("data"); m_writer.StartObject(); m_writer.String("bbox"); add_bbox(info_handler.bounds); if (info_handler.first_timestamp() != osmium::end_of_time()) { m_writer.String("timestamp"); m_writer.StartObject(); m_writer.String("first"); std::string s = info_handler.first_timestamp().to_iso(); m_writer.String(s.c_str()); m_writer.String("last"); s = info_handler.last_timestamp().to_iso(); m_writer.String(s.c_str()); m_writer.EndObject(); } m_writer.String("objects_ordered"); m_writer.Bool(info_handler.ordered); if (info_handler.ordered) { m_writer.String("multiple_versions"); m_writer.Bool(info_handler.multiple_versions); } m_writer.String("crc32"); std::stringstream ss; ss << std::hex << info_handler.crc32().checksum() << std::dec; m_writer.String(ss.str().c_str()); m_writer.String("count"); m_writer.StartObject(); m_writer.String("changesets"); m_writer.Int64(info_handler.changesets); m_writer.String("nodes"); m_writer.Int64(info_handler.nodes); m_writer.String("ways"); m_writer.Int64(info_handler.ways); m_writer.String("relations"); m_writer.Int64(info_handler.relations); m_writer.EndObject(); m_writer.String("maxid"); m_writer.StartObject(); m_writer.String("changesets"); m_writer.Int64(info_handler.largest_changeset_id()); m_writer.String("nodes"); m_writer.Int64(info_handler.largest_node_id()); m_writer.String("ways"); m_writer.Int64(info_handler.largest_way_id()); m_writer.String("relations"); m_writer.Int64(info_handler.largest_relation_id()); m_writer.EndObject(); m_writer.EndObject(); } void output() override final { m_writer.EndObject(); std::cout << m_stream.GetString() << "\n"; } }; // class JSONOutput class SimpleOutput : public Output { std::string m_get_value; public: explicit SimpleOutput(const std::string& get_value) : m_get_value(get_value) { } void file(const std::string& input_filename, const osmium::io::File& input_file) override final { if (m_get_value == "file.name") { std::cout << input_filename << "\n"; } if (m_get_value == "file.format") { std::cout << input_file.format() << "\n"; } if (m_get_value == "file.compression") { std::cout << input_file.compression() << "\n"; } if (m_get_value == "file.size") { if (input_file.filename().empty()) { std::cout << 0 << "\n"; } else { std::cout << osmium::util::file_size(input_file.filename()) << "\n"; } } } void header(const osmium::io::Header& header) override final { if (m_get_value == "header.with_history") { std::cout << yes_no(header.has_multiple_object_versions()); } for (const auto& option : header) { std::string value_name{"header.option."}; value_name.append(option.first); if (m_get_value == value_name) { std::cout << option.second << "\n"; } } } void data(const osmium::io::Header& /*header*/, const InfoHandler& info_handler) override final { if (m_get_value == "data.bbox") { std::cout << info_handler.bounds << "\n"; } if (m_get_value == "data.timestamp.first") { if (info_handler.first_timestamp() == osmium::end_of_time()) { std::cout << "\n"; } else { std::cout << info_handler.first_timestamp() << "\n"; } } if (m_get_value == "data.timestamp.last") { if (info_handler.first_timestamp() == osmium::end_of_time()) { std::cout << "\n"; } else { std::cout << info_handler.last_timestamp() << "\n"; } } if (m_get_value == "data.objects_ordered") { std::cout << (info_handler.ordered ? "yes\n" : "no\n"); } if (m_get_value == "data.multiple_versions") { if (info_handler.ordered) { std::cout << (info_handler.multiple_versions ? "yes\n" : "no\n"); } else { std::cout << "unknown\n"; } } if (m_get_value == "data.crc32") { std::cout << std::hex << info_handler.crc32().checksum() << std::dec << "\n"; } if (m_get_value == "data.count.changesets") { std::cout << info_handler.changesets << "\n"; } if (m_get_value == "data.count.nodes") { std::cout << info_handler.nodes << "\n"; } if (m_get_value == "data.count.ways") { std::cout << info_handler.ways << "\n"; } if (m_get_value == "data.count.relations") { std::cout << info_handler.relations << "\n"; } if (m_get_value == "data.maxid.changesets") { std::cout << info_handler.largest_changeset_id() << "\n"; } if (m_get_value == "data.maxid.nodes") { std::cout << info_handler.largest_node_id() << "\n"; } if (m_get_value == "data.maxid.ways") { std::cout << info_handler.largest_way_id() << "\n"; } if (m_get_value == "data.maxid.relations") { std::cout << info_handler.largest_relation_id() << "\n"; } } }; // class SimpleOutput /*************************************************************************/ bool CommandFileinfo::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("extended,e", "Extended output") ("get,g", po::value(), "Get value") ("show-variables,G", "Show variables for --get option") ("json,j", "JSON output") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_single_input_options()}; po::options_description hidden; hidden.add_options() ("input-filename", po::value(), "Input file") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filename", 1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_progress(vm); if (vm.count("extended")) { m_extended = true; } if (vm.count("json")) { m_json_output = true; } std::vector known_values = { "file.name", "file.format", "file.compression", "file.size", "header.with_history", "header.option.generator", "header.option.osmosis_replication_base_url", "header.option.osmosis_replication_sequence_number", "header.option.osmosis_replication_timestamp", "header.option.pbf_dense_nodes", "header.option.timestamp", "header.option.version", "data.bbox", "data.timestamp.first", "data.timestamp.last", "data.objects_ordered", "data.multiple_versions", "data.crc32", "data.count.nodes", "data.count.ways", "data.count.relations", "data.count.changesets", "data.maxid.nodes", "data.maxid.ways", "data.maxid.relations", "data.maxid.changesets" }; if (vm.count("show-variables")) { std::copy(known_values.cbegin(), known_values.cend(), std::ostream_iterator(std::cout, "\n")); return false; } else { setup_input_file(vm); } if (vm.count("get")) { m_get_value = vm["get"].as(); if (m_get_value.substr(0, 14) != "header.option.") { const auto& f = std::find(known_values.cbegin(), known_values.cend(), m_get_value); if (f == known_values.cend()) { throw argument_error{std::string{"Unknown value for --get/-g option '"} + m_get_value + "'. Use --show-variables/-G to see list of known values."}; } } if (m_get_value.substr(0, 5) == "data." && ! m_extended) { throw argument_error{"You need to set --extended/-e for any 'data.*' variables to be available."}; } } if (vm.count("get") && vm.count("json")) { throw argument_error{"You can not use --get/-g and --json/-j together."}; } return true; } void CommandFileinfo::show_arguments() { show_single_input_arguments(m_vout); m_vout << " other options:\n"; m_vout << " extended output: " << (m_extended ? "yes\n" : "no\n"); } bool CommandFileinfo::run() { std::unique_ptr output; if (m_json_output) { output.reset(new JSONOutput()); } else if (m_get_value.empty()) { output.reset(new HumanReadableOutput()); } else { output.reset(new SimpleOutput(m_get_value)); } output->file(m_input_filename, m_input_file); osmium::io::Reader reader{m_input_file, m_extended ? osmium::osm_entity_bits::all : osmium::osm_entity_bits::nothing}; osmium::io::Header header{reader.header()}; output->header(header); if (m_extended) { InfoHandler info_handler; osmium::ProgressBar progress_bar{reader.file_size(), display_progress()}; while (osmium::memory::Buffer buffer = reader.read()) { progress_bar.update(reader.offset()); osmium::apply(buffer, info_handler); } progress_bar.done(); output->data(header, info_handler); } reader.close(); output->output(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_fileinfo.hpp000066400000000000000000000027771315004223400206040ustar00rootroot00000000000000#ifndef COMMAND_FILEINFO_HPP #define COMMAND_FILEINFO_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "cmd.hpp" // IWYU pragma: export class CommandFileinfo : public Command, public with_single_osm_input { bool m_extended = false; bool m_json_output = false; std::string m_get_value; public: CommandFileinfo() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "fileinfo"; } const char* synopsis() const noexcept override final { return "osmium fileinfo [OPTIONS] OSM-FILE"; } }; // class CommandFileinfo #endif // COMMAND_FILEINFO_HPP osmium-tool-1.7.1/src/command_getid.cpp000066400000000000000000000361301315004223400200660ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_getid.hpp" #include "exception.hpp" #include "util.hpp" void CommandGetId::parse_and_add_id(const std::string& s) { auto p = osmium::string_to_object_id(s.c_str(), osmium::osm_entity_bits::nwr, m_default_item_type); if (p.second < 0) { throw std::runtime_error{"osmium-getid does not work with negative IDs"}; } m_ids(p.first).set(p.second); } void CommandGetId::read_id_file(std::istream& stream) { m_vout << "Reading ID file...\n"; for (std::string line; std::getline(stream, line); ) { strip_whitespace(line); const auto pos = line.find_first_of(" #"); if (pos != std::string::npos) { line.erase(pos); } if (!line.empty()) { parse_and_add_id(line); } } } bool CommandGetId::no_ids() const { return m_ids(osmium::item_type::node).empty() && m_ids(osmium::item_type::way).empty() && m_ids(osmium::item_type::relation).empty(); } std::size_t CommandGetId::count_ids() const { return m_ids(osmium::item_type::node).size() + m_ids(osmium::item_type::way).size() + m_ids(osmium::item_type::relation).size(); } bool CommandGetId::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("default-type", po::value()->default_value("node"), "Default item type") ("id-file,i", po::value>(), "Read OSM IDs from text file") ("id-osm-file,I", po::value>(), "Read OSM IDs from OSM file") ("history", "Deprecated, use --with-history instead") ("with-history,H", "Make it work with history files") ("add-referenced,r", "Recursively add referenced objects") ("verbose-ids", "Print all requested and missing IDs") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_single_input_options()}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("input-filename", po::value(), "OSM input file") ("ids", po::value>(), "OSM IDs") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filename", 1); positional.add("ids", -1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_progress(vm); setup_input_file(vm); setup_output_file(vm); if (vm.count("add-referenced")) { if (m_input_filename == "-") { throw argument_error{"Can not read OSM input from STDIN when --add-referenced/-r option is used."}; } m_add_referenced_objects = true; } if (vm.count("with-history")) { m_work_with_history = true; } if (vm.count("history")) { warning("The --history option is deprecated. Use --with-history instead.\n"); m_work_with_history = true; } if (vm.count("default-type")) { std::string t{vm["default-type"].as()}; if (t == "n" || t == "node") { m_default_item_type = osmium::item_type::node; } else if (t == "w" || t == "way") { m_default_item_type = osmium::item_type::way; } else if (t == "r" || t == "relation") { m_default_item_type = osmium::item_type::relation; } else { throw argument_error{std::string{"Unknown default type '"} + t + "' (Allowed are 'node', 'way', and 'relation')."}; } } if (vm.count("verbose-ids")) { m_vout.verbose(true); m_verbose_ids = true; } if (vm.count("id-file")) { for (const std::string& filename : vm["id-file"].as>()) { if (filename == "-") { if (m_input_filename == "-") { throw argument_error{"Can not read OSM input and IDs both from STDIN."}; } read_id_file(std::cin); } else { std::ifstream id_file{filename}; if (!id_file.is_open()) { throw argument_error{"Could not open file '" + filename + "'"}; } read_id_file(id_file); } } } if (vm.count("id-osm-file")) { for (const std::string& filename : vm["id-osm-file"].as>()) { read_id_osm_file(filename); } } if (vm.count("ids")) { std::string sids; for (const auto& s : vm["ids"].as>()) { sids += s + " "; } for (const auto& s : osmium::split_string(sids, "\t ;,/|", true)) { parse_and_add_id(s); } } if (no_ids()) { throw argument_error{"Please specify IDs to look for on command line or with option --id-file/-i or --id-osm-file/-I."}; } return true; } void CommandGetId::show_arguments() { show_single_input_arguments(m_vout); show_output_arguments(m_vout); m_vout << " other options:\n"; m_vout << " add referenced objects: " << yes_no(m_add_referenced_objects); m_vout << " work with history files: " << yes_no(m_work_with_history); m_vout << " default object type: " << osmium::item_type_to_name(m_default_item_type) << "\n"; if (m_verbose_ids) { m_vout << " looking for these ids:\n"; m_vout << " nodes:"; for (osmium::object_id_type id : m_ids(osmium::item_type::node)) { m_vout << " " << id; } m_vout << "\n"; m_vout << " ways:"; for (osmium::object_id_type id : m_ids(osmium::item_type::way)) { m_vout << " " << id; } m_vout << "\n"; m_vout << " relations:"; for (osmium::object_id_type id : m_ids(osmium::item_type::relation)) { m_vout << " " << id; } m_vout << "\n"; } else { m_vout << " looking for " << m_ids(osmium::item_type::node).size() << " node ID(s), " << m_ids(osmium::item_type::way).size() << " way ID(s), and " << m_ids(osmium::item_type::relation).size() << " relation ID(s)\n"; } } osmium::osm_entity_bits::type CommandGetId::get_needed_types() const { osmium::osm_entity_bits::type types = osmium::osm_entity_bits::nothing; if (! m_ids(osmium::item_type::node).empty()) { types |= osmium::osm_entity_bits::node; } if (! m_ids(osmium::item_type::way).empty()) { types |= osmium::osm_entity_bits::way; } if (! m_ids(osmium::item_type::relation).empty()) { types |= osmium::osm_entity_bits::relation; } return types; } void CommandGetId::add_nodes(const osmium::Way& way) { for (const auto& nr : way.nodes()) { m_ids(osmium::item_type::node).set(nr.positive_ref()); } } void CommandGetId::add_members(const osmium::Relation& relation) { for (const auto& member : relation.members()) { m_ids(member.type()).set(member.positive_ref()); } } static void print_missing_ids(const char* type, const osmium::index::IdSetDense& set) { if (set.empty()) { return; } std::cerr << "Missing " << type << " IDs:"; for (const auto& id : set) { std::cerr << ' ' << id; } std::cerr << '\n'; } void CommandGetId::read_id_osm_file(const std::string& file_name) { m_vout << "Reading OSM ID file...\n"; osmium::io::Reader reader{file_name, osmium::osm_entity_bits::object}; while (osmium::memory::Buffer buffer = reader.read()) { for (const auto& object : buffer.select()) { m_ids(object.type()).set(object.positive_id()); if (object.type() == osmium::item_type::way) { add_nodes(static_cast(object)); } else if (object.type() == osmium::item_type::relation) { add_members(static_cast(object)); } } } reader.close(); } void CommandGetId::mark_rel_ids(const osmium::index::RelationsMapIndex& rel_in_rel, osmium::object_id_type parent_id) { rel_in_rel.for_each(parent_id, [&](osmium::unsigned_object_id_type member_id) { if (m_ids(osmium::item_type::relation).check_and_set(member_id)) { mark_rel_ids(rel_in_rel, member_id); } }); } bool CommandGetId::find_relations_in_relations() { m_vout << " Reading input file to find relations in relations...\n"; osmium::index::RelationsMapStash stash; osmium::io::Reader reader{m_input_file, osmium::osm_entity_bits::relation}; while (osmium::memory::Buffer buffer = reader.read()) { for (const auto& relation : buffer.select()) { for (const auto& member : relation.members()) { if (member.type() == osmium::item_type::relation) { stash.add(member.ref(), relation.id()); } else if (m_ids(osmium::item_type::relation).get(relation.positive_id())) { if (member.type() == osmium::item_type::node) { m_ids(osmium::item_type::node).set(member.positive_ref()); } else if (member.type() == osmium::item_type::way) { m_ids(osmium::item_type::way).set(member.positive_ref()); } } } } } reader.close(); if (stash.empty()) { return false; } const auto rel_in_rel = stash.build_parent_to_member_index(); for (const osmium::unsigned_object_id_type id : m_ids(osmium::item_type::relation)) { mark_rel_ids(rel_in_rel, id); } return true; } void CommandGetId::find_nodes_and_ways_in_relations() { m_vout << " Reading input file to find nodes/ways in relations...\n"; osmium::io::Reader reader{m_input_file, osmium::osm_entity_bits::relation}; while (osmium::memory::Buffer buffer = reader.read()) { for (const auto& relation : buffer.select()) { if (m_ids(osmium::item_type::relation).get(relation.positive_id())) { for (const auto& member : relation.members()) { if (member.type() == osmium::item_type::node) { m_ids(osmium::item_type::node).set(member.positive_ref()); } else if (member.type() == osmium::item_type::way) { m_ids(osmium::item_type::way).set(member.positive_ref()); } } } } } reader.close(); } void CommandGetId::find_nodes_in_ways() { m_vout << " Reading input file to find nodes in ways...\n"; osmium::io::Reader reader{m_input_file, osmium::osm_entity_bits::way}; while (osmium::memory::Buffer buffer = reader.read()) { for (const auto& way : buffer.select()) { if (m_ids(osmium::item_type::way).get(way.positive_id())) { add_nodes(way); } } } reader.close(); } void CommandGetId::find_referenced_objects() { m_vout << "Following references...\n"; // If there are any relations we are looking for, we need to run // find_relations_in_relations() to get the member IDs of all types. bool todo = !m_ids(osmium::item_type::relation).empty(); if (todo) { todo = find_relations_in_relations(); } if (todo) { // If find_relations_in_relations() returned true, it means it found // relation members that were not in the original relations ID list. // This means we need to run find_nodes_and_ways_in_relations() to // make sure we have all node and way members of those relations, too. find_nodes_and_ways_in_relations(); } if (!m_ids(osmium::item_type::way).empty()) { find_nodes_in_ways(); } m_vout << "Done following references.\n"; } bool CommandGetId::run() { if (m_add_referenced_objects) { find_referenced_objects(); } m_vout << "Opening input file...\n"; osmium::io::Reader reader{m_input_file, get_needed_types()}; m_vout << "Opening output file...\n"; osmium::io::Header header = reader.header(); setup_header(header); osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; m_vout << "Copying matching objects to output file...\n"; osmium::ProgressBar progress_bar{reader.file_size(), display_progress()}; while (osmium::memory::Buffer buffer = reader.read()) { progress_bar.update(reader.offset()); for (const auto& object : buffer.select()) { if (m_ids(object.type()).get(object.positive_id())) { if (!m_work_with_history) { m_ids(object.type()).unset(object.positive_id()); } writer(object); } } } progress_bar.done(); m_vout << "Closing output file...\n"; writer.close(); m_vout << "Closing input file...\n"; reader.close(); if (!m_work_with_history) { if (no_ids()) { m_vout << "Found all objects.\n"; } else { m_vout << "Did not find " << count_ids() << " object(s).\n"; if (m_verbose_ids) { print_missing_ids("node", m_ids(osmium::item_type::node)); print_missing_ids("way", m_ids(osmium::item_type::way)); print_missing_ids("relation", m_ids(osmium::item_type::relation)); } } } show_memory_used(); m_vout << "Done.\n"; return m_work_with_history || no_ids(); } osmium-tool-1.7.1/src/command_getid.hpp000066400000000000000000000054011315004223400200700ustar00rootroot00000000000000#ifndef COMMAND_GETID_HPP #define COMMAND_GETID_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "cmd.hpp" // IWYU pragma: export namespace osmium { namespace index { class RelationsMapIndex; }} class CommandGetId : public Command, public with_single_osm_input, public with_osm_output { osmium::item_type m_default_item_type = osmium::item_type::node; bool m_add_referenced_objects = false; bool m_work_with_history = false; bool m_verbose_ids = false; osmium::nwr_array> m_ids; void parse_and_add_id(const std::string& s); void read_id_osm_file(const std::string& file_name); void read_id_file(std::istream& stream); osmium::osm_entity_bits::type get_needed_types() const; bool no_ids() const; std::size_t count_ids() const; void find_referenced_objects(); void add_nodes(const osmium::Way& way); void add_members(const osmium::Relation& relation); void mark_rel_ids(const osmium::index::RelationsMapIndex& rel_in_rel, osmium::object_id_type parent_id); bool find_relations_in_relations(); void find_nodes_and_ways_in_relations(); void find_nodes_in_ways(); public: CommandGetId() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "getid"; } const char* synopsis() const noexcept override final { return "osmium getid [OPTIONS] OSM-FILE ID...\n" " osmium getid [OPTIONS] OSM-FILE -i ID-FILE\n" " osmium getid [OPTIONS] OSM-FILE -I ID-OSM-FILE"; } }; // class CommandGetId #endif // COMMAND_GETID_HPP osmium-tool-1.7.1/src/command_help.cpp000066400000000000000000000062421315004223400177230ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #ifndef _MSC_VER # include #endif #include "command_help.hpp" bool CommandHelp::setup(const std::vector& arguments) { m_topic = arguments.empty() ? "help" : arguments.front(); return true; } static void show_help(const std::string& topic, const std::string& info) { #ifndef _MSC_VER // show man page on non-Windows systems std::string manpage{"osmium-"}; manpage += topic; ::execlp("man", "man", manpage.c_str(), nullptr); // if exec fails, fall thru #endif // show info string and link on Windows systems std::cout << info << "\n"; std::cout << "You'll find more documentation at http://osmcode.org/osmium-tool/\n"; } bool CommandHelp::run() { auto commands = CommandFactory::help(); if (m_topic == "help") { std::cout << "Usage: " << synopsis() << "\n\nCOMMANDS:\n"; // print command names and descriptions in a nice table for (const auto& cmd : commands) { std::cout << " " << std::setw(CommandFactory::max_command_name_length()) << std::left << cmd.first << std::setw(0) << " " << cmd.second << "\n"; } std::cout << "\nTOPICS:\n" " file-formats File formats supported by Osmium\n" " index-types Index types for storing node locations\n"; std::cout << "\nUse 'osmium COMMAND -h' for short usage information.\n" "Use 'osmium help COMMAND' for detailed information on a specific command.\n" "Use 'osmium help TOPIC' for detailed information on a specific topic.\n"; return true; } std::string description = CommandFactory::get_description(m_topic); if (!description.empty()) { show_help(m_topic, std::string{"osmium "} + m_topic + ": " + description); return true; } if (m_topic == "file-formats") { show_help("file-formats", "osmium file-formats: Supported formats are 'xml', 'pbf', and 'opl'."); return true; } if (m_topic == "index-types") { show_help("index-types", ""); return true; } std::cerr << "Unknown help topic '" << m_topic << "'.\n"; return false; } osmium-tool-1.7.1/src/command_help.hpp000066400000000000000000000025331315004223400177270ustar00rootroot00000000000000#ifndef COMMAND_HELP_HPP #define COMMAND_HELP_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "cmd.hpp" // IWYU pragma: export class CommandHelp : public Command { std::string m_topic; public: bool setup(const std::vector& arguments) override final; bool run() override final; const char* name() const noexcept override final { return "help"; } const char* synopsis() const noexcept override final { return "osmium COMMAND [ARG...]\n" " osmium --version"; } }; // class CommandHelp #endif // COMMAND_HELP_HPP osmium-tool-1.7.1/src/command_merge.cpp000066400000000000000000000144201315004223400200670ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_merge.hpp" namespace osmium { namespace io { class File; }} bool CommandMerge::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_multiple_inputs_options()}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("input-filenames", po::value>(), "Input files") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filenames", -1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_input_files(vm); setup_output_file(vm); return true; } void CommandMerge::show_arguments() { show_multiple_inputs_arguments(m_vout); show_output_arguments(m_vout); } namespace { class DataSource { using it_type = osmium::io::InputIterator; std::unique_ptr reader; it_type iterator; public: explicit DataSource(const osmium::io::File& file) : reader(new osmium::io::Reader{file}), iterator(*reader) { } bool empty() const noexcept { return iterator == it_type{}; } bool next() noexcept { ++iterator; return iterator != it_type{}; } const osmium::OSMObject* get() noexcept { return &*iterator; } }; // DataSource class QueueElement { const osmium::OSMObject* m_object; int m_data_source_index; public: QueueElement(const osmium::OSMObject* object, int data_source_index) noexcept : m_object(object), m_data_source_index(data_source_index) { } const osmium::OSMObject& object() const noexcept { return *m_object; } int data_source_index() const noexcept { return m_data_source_index; } }; // QueueElement bool operator<(const QueueElement& lhs, const QueueElement& rhs) noexcept { return lhs.object() > rhs.object(); } bool operator==(const QueueElement& lhs, const QueueElement& rhs) noexcept { return lhs.object() == rhs.object(); } bool operator!=(const QueueElement& lhs, const QueueElement& rhs) noexcept { return ! (lhs == rhs); } } // anonymous namespace bool CommandMerge::run() { m_vout << "Opening output file...\n"; osmium::io::Header header; setup_header(header); osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; if (m_input_files.size() == 1) { m_vout << "Single input file. Copying to output file...\n"; osmium::io::Reader reader{m_input_files[0]}; while (osmium::memory::Buffer buffer = reader.read()) { writer(std::move(buffer)); } } else if (m_input_files.size() == 2) { // Use simpler code when there are exactly two files to merge m_vout << "Merging 2 input files to output file...\n"; osmium::io::Reader reader1(m_input_files[0], osmium::osm_entity_bits::object); osmium::io::Reader reader2(m_input_files[1], osmium::osm_entity_bits::object); auto in1 = osmium::io::make_input_iterator_range(reader1); auto in2 = osmium::io::make_input_iterator_range(reader2); auto out = osmium::io::make_output_iterator(writer); std::set_union(in1.cbegin(), in1.cend(), in2.cbegin(), in2.cend(), out); } else { // Three or more files to merge m_vout << "Merging " << m_input_files.size() << " input files to output file...\n"; std::vector data_sources; data_sources.reserve(m_input_files.size()); std::priority_queue queue; int index = 0; for (const osmium::io::File& file : m_input_files) { data_sources.emplace_back(file); if (!data_sources.back().empty()) { queue.emplace(data_sources.back().get(), index); } ++index; } while (!queue.empty()) { auto element = queue.top(); queue.pop(); if (queue.empty() || element != queue.top()) { writer(element.object()); } const int index = element.data_source_index(); if (data_sources[index].next()) { queue.emplace(data_sources[index].get(), index); } } } m_vout << "Closing output file...\n"; writer.close(); show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_merge.hpp000066400000000000000000000026521315004223400201000ustar00rootroot00000000000000#ifndef COMMAND_MERGE_HPP #define COMMAND_MERGE_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "cmd.hpp" // IWYU pragma: export class CommandMerge : public Command, public with_multiple_osm_inputs, public with_osm_output { public: CommandMerge() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "merge"; } const char* synopsis() const noexcept override final { return "osmium merge [OPTIONS] OSM-FILE..."; } }; // class CommandMerge #endif // COMMAND_MERGE_HPP osmium-tool-1.7.1/src/command_merge_changes.cpp000066400000000000000000000111461315004223400215610ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_merge_changes.hpp" namespace osmium { namespace io { class File; }} bool CommandMergeChanges::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("simplify,s", "Simplify change") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_multiple_inputs_options()}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("input-filenames", po::value>(), "Input files") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filenames", -1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_input_files(vm); setup_output_file(vm); if (vm.count("simplify")) { m_simplify_change = true; } return true; } void CommandMergeChanges::show_arguments() { show_multiple_inputs_arguments(m_vout); show_output_arguments(m_vout); } bool CommandMergeChanges::run() { m_vout << "Opening output file...\n"; osmium::io::Header header; setup_header(header); osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; auto out = osmium::io::make_output_iterator(writer); // this will contain all the buffers with the input data std::vector changes; osmium::ObjectPointerCollection objects; // read all input files, keep the buffers around and add pointer // to each object to objects collection. m_vout << "Reading change file contents...\n"; for (osmium::io::File& change_file : m_input_files) { osmium::io::Reader reader{change_file, osmium::osm_entity_bits::object}; while (osmium::memory::Buffer buffer = reader.read()) { osmium::apply(buffer, objects); changes.push_back(std::move(buffer)); } reader.close(); } // Now we sort all objects and write them in order into the // output_buffer, flushing the output_buffer whenever it is full. if (m_simplify_change) { // If the --simplify option was given we sort with the // largest version of each object first and then only // copy this last version of any object to the output_buffer. m_vout << "Sorting change data...\n"; objects.sort(osmium::object_order_type_id_reverse_version()); m_vout << "Writing last version of each object to output...\n"; std::unique_copy(objects.cbegin(), objects.cend(), out, osmium::object_equal_type_id()); } else { // If the --simplify option was not given, this // is a straightforward sort and copy. m_vout << "Sorting change data...\n"; objects.sort(osmium::object_order_type_id_version()); m_vout << "Writing all objects to output...\n"; std::copy(objects.cbegin(), objects.cend(), out); } m_vout << "Closing output file...\n"; writer.close(); show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_merge_changes.hpp000066400000000000000000000030231315004223400215610ustar00rootroot00000000000000#ifndef COMMAND_MERGE_CHANGES_HPP #define COMMAND_MERGE_CHANGES_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "cmd.hpp" // IWYU pragma: export class CommandMergeChanges : public Command, public with_multiple_osm_inputs, public with_osm_output { bool m_simplify_change = false; public: CommandMergeChanges() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "merge-changes"; } const char* synopsis() const noexcept override final { return "osmium merge-changes [OPTIONS] OSM-CHANGE-FILE..."; } }; // class CommandMergeChanges #endif // COMMAND_MERGE_CHANGES_HPP osmium-tool-1.7.1/src/command_renumber.cpp000066400000000000000000000261111315004223400206070ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 # include #endif #include #include #include #include #include #include #include #include #include #include #include #include "command_renumber.hpp" namespace osmium { namespace io { class File; }} osmium::object_id_type id_map::operator()(osmium::object_id_type id) { // Search for id in m_extra_ids and return if found. const auto it = m_extra_ids.find(id); if (it != m_extra_ids.end()) { return it->second; } // New ID is larger than all existing IDs. Add it to end and return. if (m_ids.empty() || osmium::id_order{}(m_ids.back(), id)) { m_ids.push_back(id); return m_ids.size(); } const auto element = std::lower_bound(m_ids.cbegin(), m_ids.cend(), id, osmium::id_order{}); // Old ID not found in m_ids, add to m_extra_ids. if (element == m_ids.cend() || *element != id) { m_ids.push_back(m_ids.back()); m_extra_ids[id] = m_ids.size(); return m_ids.size(); } // Old ID found in m_ids, return. return osmium::object_id_type(std::distance(m_ids.cbegin(), element) + 1); } void id_map::write(int fd) { for (const auto& m : m_extra_ids) { m_ids[m.second - 1] = m.first; } osmium::io::detail::reliable_write( fd, reinterpret_cast(m_ids.data()), sizeof(osmium::object_id_type) * m_ids.size() ); } void id_map::read(int fd, std::size_t file_size) { const auto num_elements = file_size / sizeof(osmium::object_id_type); m_ids.reserve(num_elements); osmium::util::TypedMemoryMapping mapping{num_elements, osmium::util::MemoryMapping::mapping_mode::readonly, fd}; osmium::object_id_type last_id = 0; for (osmium::object_id_type id : mapping) { if (osmium::id_order{}(last_id, id)) { m_ids.push_back(id); last_id = id; } else { m_ids.push_back(last_id); m_extra_ids[id] = m_ids.size(); } } } bool CommandRenumber::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("index-directory,i", po::value(), "Index directory") ("object-type,t", po::value>(), "Renumber only objects of given type (node, way, relation)") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_single_input_options()}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("input-filename", po::value(), "Input file") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filename", 1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_progress(vm); setup_object_type_nwr(vm); setup_input_file(vm); setup_output_file(vm); if (vm.count("index-directory")) { m_index_directory = vm["index-directory"].as(); } return true; } void CommandRenumber::show_arguments() { show_single_input_arguments(m_vout); show_output_arguments(m_vout); m_vout << " other options:\n"; m_vout << " index directory: " << m_index_directory << "\n"; m_vout << " object types that will be renumbered:"; if (osm_entity_bits() & osmium::osm_entity_bits::node) { m_vout << " node"; } if (osm_entity_bits() & osmium::osm_entity_bits::way) { m_vout << " way"; } if (osm_entity_bits() & osmium::osm_entity_bits::relation) { m_vout << " relation"; } m_vout << "\n"; } void CommandRenumber::renumber(osmium::memory::Buffer& buffer) { for (auto& object : buffer.select()) { switch (object.type()) { case osmium::item_type::node: if (osm_entity_bits() & osmium::osm_entity_bits::node) { m_check_order.node(static_cast(object)); object.set_id(m_id_map(osmium::item_type::node)(object.id())); } break; case osmium::item_type::way: if (osm_entity_bits() & osmium::osm_entity_bits::way) { m_check_order.way(static_cast(object)); object.set_id(m_id_map(osmium::item_type::way)(object.id())); } if (osm_entity_bits() & osmium::osm_entity_bits::node) { for (auto& ref : static_cast(object).nodes()) { ref.set_ref(m_id_map(osmium::item_type::node)(ref.ref())); } } break; case osmium::item_type::relation: if (osm_entity_bits() & osmium::osm_entity_bits::relation) { m_check_order.relation(static_cast(object)); object.set_id(m_id_map(osmium::item_type::relation)(object.id())); } for (auto& member : static_cast(object).members()) { if (osm_entity_bits() & osmium::osm_entity_bits::from_item_type(member.type())) { member.set_ref(m_id_map(member.type())(member.ref())); } } break; default: break; } } } std::string CommandRenumber::filename(const char* name) const { return m_index_directory + "/" + name + ".idx"; } void CommandRenumber::read_index(osmium::item_type type) { const std::string f{filename(osmium::item_type_to_name(type))}; const int fd = ::open(f.c_str(), O_RDWR); if (fd < 0) { // if the file is not there we don't have to read anything and can return if (errno == ENOENT) { return; } throw std::runtime_error{std::string{"Could not open file '"} + f + "': " + std::strerror(errno)}; } #ifdef _WIN32 _setmode(fd, _O_BINARY); #endif const std::size_t file_size = osmium::util::file_size(fd); if (file_size % sizeof(osmium::object_id_type) != 0) { throw std::runtime_error{std::string{"Index file '"} + f + "' has wrong file size"}; } m_id_map(type).read(fd, file_size); close(fd); } void CommandRenumber::write_index(osmium::item_type type) { if (!(osm_entity_bits() & osmium::osm_entity_bits::from_item_type(type))) { return; } const std::string f{filename(osmium::item_type_to_name(type))}; const int fd = ::open(f.c_str(), O_WRONLY | O_CREAT, 0666); if (fd < 0) { throw std::runtime_error{std::string{"Could not open file '"} + f + "': " + std::strerror(errno)}; } #ifdef _WIN32 _setmode(fd, _O_BINARY); #endif m_id_map(type).write(fd); close(fd); } void read_relations(const osmium::io::File& input_file, id_map& map) { osmium::io::Reader reader_pass1{input_file, osmium::osm_entity_bits::relation}; auto input = osmium::io::make_input_iterator_range(reader_pass1); for (const osmium::Relation& relation : input) { map(relation.id()); } reader_pass1.close(); } bool CommandRenumber::run() { if (!m_index_directory.empty()) { m_vout << "Reading index files...\n"; read_index(osmium::item_type::node); read_index(osmium::item_type::way); read_index(osmium::item_type::relation); m_vout << " Nodes index contains " << m_id_map(osmium::item_type::node).size() << " items\n"; m_vout << " Ways index contains " << m_id_map(osmium::item_type::way).size() << " items\n"; m_vout << " Relations index contains " << m_id_map(osmium::item_type::relation).size() << " items\n"; } if (osm_entity_bits() & osmium::osm_entity_bits::relation) { m_vout << "First pass through input file (reading relations)...\n"; read_relations(m_input_file, m_id_map(osmium::item_type::relation)); } else { m_vout << "No first pass through input file, because relation IDs are not mapped.\n"; } m_vout << "Second pass through input file...\n"; osmium::io::Reader reader_pass2{m_input_file}; osmium::io::Header header = reader_pass2.header(); setup_header(header); header.set("xml_josm_upload", "false"); osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; osmium::ProgressBar progress_bar{reader_pass2.file_size(), display_progress()}; while (osmium::memory::Buffer buffer = reader_pass2.read()) { progress_bar.update(reader_pass2.offset()); renumber(buffer); writer(std::move(buffer)); } progress_bar.done(); reader_pass2.close(); m_vout << "Closing output file...\n"; writer.close(); if (!m_index_directory.empty()) { m_vout << "Writing index files...\n"; write_index(osmium::item_type::node); write_index(osmium::item_type::way); write_index(osmium::item_type::relation); } if (osm_entity_bits() & osmium::osm_entity_bits::node) { m_vout << "Largest (referenced) node id: " << m_id_map(osmium::item_type::node).size() << "\n"; } if (osm_entity_bits() & osmium::osm_entity_bits::way) { m_vout << "Largest (referenced) way id: " << m_id_map(osmium::item_type::way).size() << "\n"; } if (osm_entity_bits() & osmium::osm_entity_bits::relation) { m_vout << "Largest (referenced) relation id: " << m_id_map(osmium::item_type::relation).size() << "\n"; } show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_renumber.hpp000066400000000000000000000077051315004223400206240ustar00rootroot00000000000000#ifndef COMMAND_RENUMBER_HPP #define COMMAND_RENUMBER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include "cmd.hpp" // IWYU pragma: export /** * Holds the mapping from old IDs to new IDs of one object type. */ class id_map { // Internally this uses two different means of storing the mapping: // // Most of the old IDs are stored in a sorted vector. The index into the // vector is the new ID. All IDs from the nodes, ways, and relations // themselves will end up here. std::vector m_ids; // For IDs that can't be written into the sorted vector because this would // destroy the sorting, a hash map is used. These are the IDs not read // in order, ie the node IDs referenced from the ways and the member IDs // referenced from the relations. std::unordered_map m_extra_ids; // Because we still have to allocate unique new IDs for the mappings // ending up in m_extra_ids, we add dummy IDs of the same value as the // last one to the end of the m_ids vector. This gives us new IDs without // destroying the ordering of m_ids. But to find a new ID from an old ID // in m_ids we have to take the first of potentially several identical // IDs we find (using std::lower_bound), its position is then the new ID. public: id_map() = default; // Map from old ID to new ID. If the old ID has been seen before, it will // be returned, otherwise a new ID will be allocated and stored. osmium::object_id_type operator()(osmium::object_id_type id); // Write the mappings into a file in binary form. This will first copy // the mappings from m_extra_ids into the m_ids vector. After this // operation this object becomes unusable! void write(int fd); // Read the mappings from a binary file into m_ids and m_extra_ids. void read(int fd, std::size_t file_size); // The number of mappings currently existing. Also the last allocated // new ID. std::size_t size() const noexcept { return m_ids.size(); } }; // class id_map class CommandRenumber : public Command, public with_single_osm_input, public with_osm_output { std::string m_index_directory; osmium::handler::CheckOrder m_check_order; // id mappings for nodes, ways, and relations osmium::nwr_array m_id_map; void renumber(osmium::memory::Buffer& buffer); std::string filename(const char* name) const; void read_index(osmium::item_type type); void write_index(osmium::item_type type); public: CommandRenumber() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "renumber"; } const char* synopsis() const noexcept override final { return "osmium renumber [OPTIONS] OSM-FILE"; } }; // class CommandRenumber #endif // COMMAND_RENUMBER_HPP osmium-tool-1.7.1/src/command_show.cpp000066400000000000000000000160531315004223400177540ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #ifndef _MSC_VER # include # include #endif #include #include #include #include #include #include "command_show.hpp" #include "exception.hpp" #include "util.hpp" #ifndef _MSC_VER void CommandShow::setup_pager_from_env() noexcept { m_pager = "less"; const char* pager = ::getenv("OSMIUM_PAGER"); if (pager) { m_pager = pager; } else { pager = ::getenv("PAGER"); if (pager) { m_pager = pager; } } if (m_pager == "cat") { m_pager = ""; } } #endif bool CommandShow::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("format-debug,d", "Use debug format") ("format-opl,o", "Use OPL format") ("format-xml,x", "Use XML format") #ifndef _MSC_VER ("no-pager", "Do not run pager program") #endif ("object-type,t", po::value>(), "Read only objects of given type (node, way, relation, changeset)") ("output-format,f", po::value(), "Format of output file") ; po::options_description opts_common{add_common_options(false)}; po::options_description opts_input{add_single_input_options()}; po::options_description hidden; hidden.add_options() ("input-filename", po::value(), "Input file") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filename", 1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_object_type_nwrc(vm); setup_input_file(vm); #ifndef _MSC_VER if (vm.count("no-pager")) { m_pager = ""; } else { setup_pager_from_env(); } #endif if (vm.count("output-format") && vm.count("format-debug") && vm.count("format-opl") && vm.count("format-xml")) { throw argument_error{"You can only use at most one of the following options: --output-format/-f, --format-debug/-d, --format-opl/-o, and --format-xml/-x."}; } if (vm.count("output-format")) { m_output_format = vm["output-format"].as(); } else if (vm.count("format-debug")) { m_output_format = "debug,color=true"; } else if (vm.count("format-opl")) { m_output_format = "opl"; } else if (vm.count("format-xml")) { m_output_format = "xml"; } else { const char* output_format_from_env = ::getenv("OSMIUM_SHOW_FORMAT"); if (output_format_from_env) { m_output_format = output_format_from_env; } } m_color_output = m_output_format.find("color=true") != std::string::npos; return true; } void CommandShow::show_arguments() { show_single_input_arguments(m_vout); m_vout << " other options:\n"; m_vout << " file format: " << m_output_format << "\n"; m_vout << " use color: " << yes_no(m_color_output); m_vout << " use pager: " << (m_pager == "" ? "(no pager)" : m_pager) << "\n"; show_object_types(m_vout); } #ifndef _MSC_VER static int execute_pager(const std::string& pager, bool with_color) { int pipefd[2]; if (::pipe(pipefd) < 0) { throw std::system_error{errno, std::system_category(), "Could not run pager: pipe() call failed"}; } const pid_t pid = fork(); if (pid < 0) { throw std::system_error{errno, std::system_category(), "Could not run pager: fork() call failed"}; } if (pid == 0) { // child ::close(pipefd[1]); // close write end of the pipe ::close(0); // close stdin if (::dup2(pipefd[0], 0) < 0) { // put end of pipe as stdin std::exit(1); } if (with_color && pager.substr(pager.size() - 4, 4) == "less") { ::execlp(pager.c_str(), pager.c_str(), "-R", nullptr); } else { // execute pager without arguments ::execlp(pager.c_str(), pager.c_str(), nullptr); } // Exec will either succeed and never return here, or it fails and // we'll exit. std::exit(1); } // parent ::close(pipefd[0]); // close read end of the pipe if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { throw std::system_error{errno, std::system_category(), "Could not run pager: signal() call failed"}; } return pipefd[1]; } #endif bool CommandShow::run() { osmium::io::Reader reader{m_input_file, osm_entity_bits()}; osmium::io::Header header{reader.header()}; if (m_pager.empty()) { osmium::io::File file{"-", m_output_format}; osmium::io::Writer writer{file, header}; while (osmium::memory::Buffer buffer = reader.read()) { writer(std::move(buffer)); } writer.close(); } else { #ifndef _MSC_VER const int fd = execute_pager(m_pager, m_color_output); ::close(1); // close stdout if (::dup2(fd, 1) < 0) { // put end of pipe as stdout throw std::system_error{errno, std::system_category(), "Could not run pager: dup2() call failed"}; } osmium::io::File file{"-", m_output_format}; osmium::io::Writer writer{file, header}; try { while (osmium::memory::Buffer buffer = reader.read()) { writer(std::move(buffer)); } } catch (const std::system_error& e) { if (e.code().value() != EPIPE) { throw; } } close(fd); writer.close(); int status = 0; const int pid = ::wait(&status); if (pid < 0) { throw std::system_error{errno, std::system_category(), "Could not run pager: wait() call failed"}; } if (WIFEXITED(status) && WEXITSTATUS(status) == 1) { throw argument_error{std::string{"Could not run pager '"} + m_pager + "'"}; } #endif } reader.close(); return true; } osmium-tool-1.7.1/src/command_show.hpp000066400000000000000000000030271315004223400177560ustar00rootroot00000000000000#ifndef COMMAND_SHOW_HPP #define COMMAND_SHOW_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "cmd.hpp" // IWYU pragma: export class CommandShow : public Command, public with_single_osm_input { std::string m_output_format{"debug,color=true"}; std::string m_pager; bool m_color_output; void setup_pager_from_env() noexcept; public: CommandShow() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "show"; } const char* synopsis() const noexcept override final { return "osmium show [OPTIONS] OSM-FILE"; } }; // class CommandShow #endif // COMMAND_SHOW_HPP osmium-tool-1.7.1/src/command_sort.cpp000066400000000000000000000073131315004223400177620ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_sort.hpp" bool CommandSort::setup(const std::vector& arguments) { po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_multiple_inputs_options()}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("input-filenames", po::value>(), "OSM input files") ; po::options_description desc; desc.add(opts_common).add(opts_input).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filenames", -1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_input_files(vm); setup_output_file(vm); if (vm.count("input-filenames")) { m_filenames = vm["input-filenames"].as>(); } return true; } void CommandSort::show_arguments() { show_multiple_inputs_arguments(m_vout); show_output_arguments(m_vout); } bool CommandSort::run() { std::vector data; osmium::ObjectPointerCollection objects; osmium::Box bounding_box; m_vout << "Reading contents of input files...\n"; for (const std::string& file_name : m_filenames) { osmium::io::Reader reader{file_name, osmium::osm_entity_bits::object}; osmium::io::Header header{reader.header()}; bounding_box.extend(header.joined_boxes()); while (osmium::memory::Buffer buffer = reader.read()) { osmium::apply(buffer, objects); data.push_back(std::move(buffer)); } reader.close(); } m_vout << "Opening output file...\n"; osmium::io::Header header; setup_header(header); if (bounding_box) { header.add_box(bounding_box); } osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; m_vout << "Sorting data...\n"; objects.sort(osmium::object_order_type_id_version()); m_vout << "Writing out sorted data...\n"; auto out = osmium::io::make_output_iterator(writer); std::copy(objects.begin(), objects.end(), out); m_vout << "Closing output file...\n"; writer.close(); show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_sort.hpp000066400000000000000000000027151315004223400177700ustar00rootroot00000000000000#ifndef COMMAND_SORT_HPP #define COMMAND_SORT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "cmd.hpp" // IWYU pragma: export class CommandSort : public Command, public with_multiple_osm_inputs, public with_osm_output { std::vector m_filenames; public: CommandSort() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "sort"; } const char* synopsis() const noexcept override final { return "osmium sort [OPTIONS] OSM-FILE..."; } }; // class CommandSort #endif // COMMAND_SORT_HPP osmium-tool-1.7.1/src/command_tags_filter.cpp000066400000000000000000000254001315004223400212730ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_tags_filter.hpp" #include "exception.hpp" #include "util.hpp" void CommandTagsFilter::add_filter(osmium::osm_entity_bits::type entities, const osmium::TagMatcher& matcher) { if (entities & osmium::osm_entity_bits::node) { m_filters(osmium::item_type::node).add_rule(true, matcher); } if (entities & osmium::osm_entity_bits::way) { m_filters(osmium::item_type::way).add_rule(true, matcher); } if (entities & osmium::osm_entity_bits::relation) { m_filters(osmium::item_type::relation).add_rule(true, matcher); } } void CommandTagsFilter::parse_and_add_expression(const std::string& expression) { const auto p = get_filter_expression(expression); add_filter(p.first, get_tag_matcher(p.second)); } void CommandTagsFilter::read_expressions_file(const std::string& file_name) { m_vout << "Reading expressions file...\n"; std::ifstream file{file_name}; if (!file.is_open()) { throw argument_error{"Could not open file '" + file_name + "'"}; } for (std::string line; std::getline(file, line); ) { const auto pos = line.find_first_of('#'); if (pos != std::string::npos) { line.erase(pos); } if (!line.empty()) { if (line.back() == '\r') { line.resize(line.size() - 1); } parse_and_add_expression(line); } } } bool CommandTagsFilter::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("expressions,e", po::value(), "Read filter expressions from file") ("invert-match,i", "Invert the sense of matching, exclude objects with matching tags") ("omit-referenced,R", "Omit referenced objects") ; po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_single_input_options()}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("input-filename", po::value(), "OSM input file") ("expression-list", po::value>(), "Filter expressions") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_input).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filename", 1); positional.add("expression-list", -1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_progress(vm); setup_input_file(vm); setup_output_file(vm); if (vm.count("omit-referenced")) { m_add_referenced_objects = false; } else if (m_input_filename == "-") { throw argument_error{"Can not read OSM input from STDIN (unless --omit-referenced/-R option is used)."}; } if (vm.count("invert-match")) { m_invert_match = true; } if (vm.count("expression-list")) { for (const auto& e : vm["expression-list"].as>()) { parse_and_add_expression(e); } } if (vm.count("expressions")) { read_expressions_file(vm["expressions"].as()); } return true; } void CommandTagsFilter::show_arguments() { show_single_input_arguments(m_vout); show_output_arguments(m_vout); m_vout << " other options:\n"; m_vout << " add referenced objects: " << yes_no(m_add_referenced_objects); m_vout << " looking for tags...\n"; m_vout << " on nodes: " << yes_no(!m_filters(osmium::item_type::node).empty()); m_vout << " on ways: " << yes_no(!m_filters(osmium::item_type::way).empty()); m_vout << " on relations: " << yes_no(!m_filters(osmium::item_type::relation).empty()); } osmium::osm_entity_bits::type CommandTagsFilter::get_needed_types() const { osmium::osm_entity_bits::type types = osmium::osm_entity_bits::nothing; if (! m_ids(osmium::item_type::node).empty() || !m_filters(osmium::item_type::node).empty()) { types |= osmium::osm_entity_bits::node; } if (! m_ids(osmium::item_type::way).empty() || !m_filters(osmium::item_type::way).empty()) { types |= osmium::osm_entity_bits::way; } if (! m_ids(osmium::item_type::relation).empty() || !m_filters(osmium::item_type::relation).empty()) { types |= osmium::osm_entity_bits::relation; } return types; } void CommandTagsFilter::add_nodes(const osmium::Way& way) { for (const auto& nr : way.nodes()) { m_ids(osmium::item_type::node).set(nr.positive_ref()); } } void CommandTagsFilter::add_members(const osmium::Relation& relation) { for (const auto& member : relation.members()) { m_ids(member.type()).set(member.positive_ref()); } } void CommandTagsFilter::mark_rel_ids(const osmium::index::RelationsMapIndex& rel_in_rel, osmium::object_id_type parent_id) { rel_in_rel.for_each(parent_id, [&](osmium::unsigned_object_id_type member_id) { if (m_ids(osmium::item_type::relation).check_and_set(member_id)) { mark_rel_ids(rel_in_rel, member_id); } }); } bool CommandTagsFilter::find_relations_in_relations() { const auto& filter = m_filters(osmium::item_type::relation); m_vout << " Reading input file to find relations in relations...\n"; osmium::index::RelationsMapStash stash; osmium::io::Reader reader{m_input_file, osmium::osm_entity_bits::relation}; while (osmium::memory::Buffer buffer = reader.read()) { for (const auto& relation : buffer.select()) { stash.add_members(relation); if (osmium::tags::match_any_of(relation.tags(), filter) != m_invert_match) { m_ids(osmium::item_type::relation).set(relation.positive_id()); } } } reader.close(); if (stash.empty()) { return false; } const auto rel_in_rel = stash.build_parent_to_member_index(); for (const osmium::unsigned_object_id_type id : m_ids(osmium::item_type::relation)) { mark_rel_ids(rel_in_rel, id); } return true; } void CommandTagsFilter::find_nodes_and_ways_in_relations() { m_vout << " Reading input file to find nodes/ways in relations...\n"; osmium::io::Reader reader{m_input_file, osmium::osm_entity_bits::relation}; while (osmium::memory::Buffer buffer = reader.read()) { for (const auto& relation : buffer.select()) { if (m_ids(osmium::item_type::relation).get(relation.positive_id())) { for (const auto& member : relation.members()) { if (member.type() == osmium::item_type::node) { m_ids(osmium::item_type::node).set(member.positive_ref()); } else if (member.type() == osmium::item_type::way) { m_ids(osmium::item_type::way).set(member.positive_ref()); } } } } } reader.close(); } void CommandTagsFilter::find_nodes_in_ways() { m_vout << " Reading input file to find nodes in ways...\n"; osmium::io::Reader reader{m_input_file, osmium::osm_entity_bits::way}; while (osmium::memory::Buffer buffer = reader.read()) { for (const auto& way : buffer.select()) { if (m_ids(osmium::item_type::way).get(way.positive_id())) { add_nodes(way); } else if (osmium::tags::match_any_of(way.tags(), m_filters(osmium::item_type::way)) != m_invert_match) { m_ids(osmium::item_type::way).set(way.positive_id()); add_nodes(way); } } } reader.close(); } void CommandTagsFilter::find_referenced_objects() { m_vout << "Following references...\n"; bool todo = !m_filters(osmium::item_type::relation).empty(); if (todo) { todo = find_relations_in_relations(); } if (todo) { find_nodes_and_ways_in_relations(); } if (!m_ids(osmium::item_type::way).empty() || !m_filters(osmium::item_type::way).empty()) { find_nodes_in_ways(); } m_vout << "Done following references.\n"; } bool CommandTagsFilter::run() { if (m_add_referenced_objects) { find_referenced_objects(); } m_vout << "Opening input file...\n"; osmium::io::Reader reader{m_input_file, get_needed_types()}; m_vout << "Opening output file...\n"; osmium::io::Header header = reader.header(); setup_header(header); osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; m_vout << "Copying matching objects to output file...\n"; osmium::ProgressBar progress_bar{reader.file_size(), display_progress()}; while (osmium::memory::Buffer buffer = reader.read()) { progress_bar.update(reader.offset()); for (const auto& object : buffer.select()) { if (m_ids(object.type()).get(object.positive_id())) { writer(object); } else if (!m_add_referenced_objects || object.type() == osmium::item_type::node) { const auto& filter = m_filters(object.type()); if (osmium::tags::match_any_of(object.tags(), filter) != m_invert_match) { writer(object); } } } } progress_bar.done(); m_vout << "Closing output file...\n"; writer.close(); m_vout << "Closing input file...\n"; reader.close(); show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_tags_filter.hpp000066400000000000000000000053231315004223400213020ustar00rootroot00000000000000#ifndef COMMAND_TAGS_FILTER_HPP #define COMMAND_TAGS_FILTER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include "cmd.hpp" // IWYU pragma: export namespace osmium { namespace index { class RelationsMapIndex; }} class CommandTagsFilter : public Command, public with_single_osm_input, public with_osm_output { bool m_add_referenced_objects = true; bool m_invert_match = false; osmium::nwr_array m_filters; osmium::nwr_array> m_ids; osmium::osm_entity_bits::type get_needed_types() const; void find_referenced_objects(); void add_nodes(const osmium::Way& way); void add_members(const osmium::Relation& relation); void mark_rel_ids(const osmium::index::RelationsMapIndex& rel_in_rel, osmium::object_id_type id); bool find_relations_in_relations(); void find_nodes_and_ways_in_relations(); void find_nodes_in_ways(); void add_filter(osmium::osm_entity_bits::type entities, const osmium::TagMatcher& matcher); void parse_and_add_expression(const std::string& expression); void read_expressions_file(const std::string& file_name); public: CommandTagsFilter() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "tags-filter"; } const char* synopsis() const noexcept override final { return "osmium tags-filter [OPTIONS] OSM-FILE FILTER-EXPRESSION...\n" " osmium tags-filter [OPTIONS] --expressions=FILE OSM-FILE"; } }; // class CommandTagsFilter #endif // COMMAND_TAGS_FILTER_HPP osmium-tool-1.7.1/src/command_time_filter.cpp000066400000000000000000000126451315004223400213020ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "command_time_filter.hpp" #include "exception.hpp" #include "util.hpp" bool CommandTimeFilter::setup(const std::vector& arguments) { po::options_description opts_common{add_common_options()}; po::options_description opts_input{add_single_input_options()}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("input-filename", po::value(), "OSM input file") ("time-from", po::value(), "Start of time range") ("time-to", po::value(), "End of time range") ; po::options_description desc; desc.add(opts_common).add(opts_input).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("input-filename", 1); positional.add("time-from", 1); positional.add("time-to", 1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); setup_common(vm, desc); setup_input_file(vm); setup_output_file(vm); m_from = osmium::Timestamp(std::time(0)); m_to = m_from; if (vm.count("time-from")) { const auto ts = vm["time-from"].as(); try { m_from = osmium::Timestamp{ts}; } catch (const std::invalid_argument&) { throw argument_error{"Wrong format for (first) timestamp (use YYYY-MM-DDThh:mm:ssZ)."}; } m_to = m_from; } if (vm.count("time-to")) { const auto ts = vm["time-to"].as(); try { m_to = osmium::Timestamp{ts}; } catch (const std::invalid_argument&) { throw argument_error{"Wrong format for second timestamp (use YYYY-MM-DDThh:mm:ssZ)."}; } } if (m_from > m_to) { throw argument_error{"Second timestamp is before first one."}; } if (m_from == m_to) { // point in time if (m_output_file.has_multiple_object_versions()) { warning("You are writing to a file marked as having multiple object versions,\n" "but there will be only a single version of each object.\n"); } } else { // time range if (!m_output_file.has_multiple_object_versions()) { warning("You are writing to a file marked as having a single object version,\n" "but there might be multiple versions of each object.\n"); } } return true; } void CommandTimeFilter::show_arguments() { show_single_input_arguments(m_vout); show_output_arguments(m_vout); m_vout << " other options:\n"; m_vout << " Filtering from time " << m_from.to_iso() << " to " << m_to.to_iso() << "\n"; } bool CommandTimeFilter::run() { m_vout << "Opening input file...\n"; osmium::io::Reader reader{m_input_file, osmium::osm_entity_bits::object}; m_vout << "Opening output file...\n"; osmium::io::Header header{reader.header()}; setup_header(header); osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; m_vout << "Filter data while copying it from input to output...\n"; auto input = osmium::io::make_input_iterator_range(reader); auto diff_begin = osmium::make_diff_iterator(input.begin(), input.end()); auto diff_end = osmium::make_diff_iterator(input.end(), input.end()); auto out = osmium::io::make_output_iterator(writer); if (m_from == m_to) { std::copy_if( diff_begin, diff_end, out, [this](const osmium::DiffObject& d){ return d.is_visible_at(m_from); }); } else { std::copy_if( diff_begin, diff_end, out, [this](const osmium::DiffObject& d){ return d.is_between(m_from, m_to); }); } m_vout << "Closing output file...\n"; writer.close(); m_vout << "Closing input file...\n"; reader.close(); show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.7.1/src/command_time_filter.hpp000066400000000000000000000032321315004223400212770ustar00rootroot00000000000000#ifndef COMMAND_TIME_FILTER_HPP #define COMMAND_TIME_FILTER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "cmd.hpp" // IWYU pragma: export class CommandTimeFilter : public Command, public with_single_osm_input, public with_osm_output { osmium::Timestamp m_from; osmium::Timestamp m_to; public: CommandTimeFilter() = default; bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run() override final; const char* name() const noexcept override final { return "time-filter"; } const char* synopsis() const noexcept override final { return "osmium time-filter [OPTIONS] OSM-HISTORY-FILE [TIME]\n" " osmium time-filter [OPTIONS] OSM-HISTORY-FILE FROM-TIME TO-TIME"; } }; // class CommandTimeFilter #endif // COMMAND_TIME_FILTER_HPP osmium-tool-1.7.1/src/commands.cpp000066400000000000000000000060561315004223400171010ustar00rootroot00000000000000 #include "command_add_locations_to_ways.hpp" #include "command_apply_changes.hpp" #include "command_cat.hpp" #include "command_changeset_filter.hpp" #include "command_check_refs.hpp" #include "command_derive_changes.hpp" #include "command_diff.hpp" #include "command_export.hpp" #include "command_extract.hpp" #include "command_fileinfo.hpp" #include "command_getid.hpp" #include "command_help.hpp" #include "command_merge_changes.hpp" #include "command_merge.hpp" #include "command_renumber.hpp" #include "command_show.hpp" #include "command_sort.hpp" #include "command_tags_filter.hpp" #include "command_time_filter.hpp" void register_commands() { CommandFactory::add("add-locations-to-ways", "Add node locations to ways", []() { return new CommandAddLocationsToWays(); }); CommandFactory::add("apply-changes", "Apply OSM change files to OSM data file", []() { return new CommandApplyChanges(); }); CommandFactory::add("cat", "Concatenate OSM files and convert to different formats", []() { return new CommandCat(); }); CommandFactory::add("changeset-filter", "Filter OSM changesets by different criteria", []() { return new CommandChangesetFilter(); }); CommandFactory::add("check-refs", "Check referential integrity of an OSM file", []() { return new CommandCheckRefs(); }); CommandFactory::add("derive-changes", "Create OSM change files from two OSM data files", []() { return new CommandDeriveChanges(); }); CommandFactory::add("diff", "Display differences between OSM files", []() { return new CommandDiff(); }); CommandFactory::add("export", "Export OSM data", []() { return new CommandExport(); }); CommandFactory::add("extract", "Create geographic extract", []() { return new CommandExtract(); }); CommandFactory::add("fileinfo", "Show information about OSM file", []() { return new CommandFileinfo(); }); CommandFactory::add("getid", "Get objects with given ID from OSM file", []() { return new CommandGetId(); }); CommandFactory::add("help", "Show osmium help", []() { return new CommandHelp(); }); CommandFactory::add("merge-changes", "Merge several OSM change files into one", []() { return new CommandMergeChanges(); }); CommandFactory::add("merge", "Merge several sorted OSM files into one", []() { return new CommandMerge(); }); CommandFactory::add("renumber", "Renumber IDs in OSM file", []() { return new CommandRenumber(); }); CommandFactory::add("show", "Show OSM file contents", []() { return new CommandShow(); }); CommandFactory::add("sort", "Sort OSM data files", []() { return new CommandSort(); }); CommandFactory::add("tags-filter", "Filter OSM data based on tags", []() { return new CommandTagsFilter(); }); CommandFactory::add("time-filter", "Filter OSM data from a point in time or a time span out of a history file", []() { return new CommandTimeFilter(); }); } osmium-tool-1.7.1/src/exception.hpp000066400000000000000000000035571315004223400173060ustar00rootroot00000000000000#ifndef EXCEPTION_HPP #define EXCEPTION_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include /** * Thrown when there is a problem with the command line arguments. */ struct argument_error : std::runtime_error { explicit argument_error(const char* message) : std::runtime_error(message) { } explicit argument_error(const std::string& message) : std::runtime_error(message) { } }; /** * Thrown when there is a problem with parsing a JSON config file. */ struct config_error : public std::runtime_error { explicit config_error(const char* message) : std::runtime_error(message) { } explicit config_error(const std::string& message) : std::runtime_error(message) { } }; // struct config_error /** * Thrown when there is a problem with parsing a GeoJSON file. */ struct geojson_error : public std::runtime_error { explicit geojson_error(const char* message) : std::runtime_error(message) { } explicit geojson_error(const std::string& message) : std::runtime_error(message) { } }; // struct geojson_error #endif // EXCEPTION_HPP osmium-tool-1.7.1/src/export/000077500000000000000000000000001315004223400161065ustar00rootroot00000000000000osmium-tool-1.7.1/src/export/export_format.hpp000066400000000000000000000031061315004223400215100ustar00rootroot00000000000000#ifndef EXPORT_EXPORT_FORMAT_HPP #define EXPORT_EXPORT_FORMAT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "options.hpp" class ExportFormat { const options_type& m_options; protected: std::uint64_t m_count; explicit ExportFormat(const options_type& options) : m_options(options), m_count(0) { } public: const options_type& options() const noexcept { return m_options; } std::uint64_t count() const noexcept { return m_count; } virtual ~ExportFormat() = default; virtual void node(const osmium::Node&) = 0; virtual void way(const osmium::Way&) = 0; virtual void area(const osmium::Area&) = 0; virtual void close() = 0; }; // class ExportFormat #endif // EXPORT_EXPORT_FORMAT_HPP osmium-tool-1.7.1/src/export/export_format_json.cpp000066400000000000000000000146371315004223400225470ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "export_format_json.hpp" static constexpr const std::size_t initial_buffer_size = 1024 * 1024; static constexpr const std::size_t flush_buffer_size = 800 * 1024; static void add_to_stream(rapidjson::StringBuffer& stream, const char* s) { while (*s) { stream.Put(*s++); } } ExportFormatJSON::ExportFormatJSON(const std::string& output_format, const std::string& output_filename, osmium::io::overwrite overwrite, osmium::io::fsync fsync, const options_type& options) : ExportFormat(options), m_fd(osmium::io::detail::open_for_writing(output_filename, overwrite)), m_fsync(fsync), m_text_sequence_format(output_format == "geojsonseq"), m_with_record_separator(m_text_sequence_format && options.print_record_separator), m_stream(), m_committed_size(0), m_writer(m_stream), m_factory(m_writer) { m_stream.Reserve(initial_buffer_size); if (!m_text_sequence_format) { add_to_stream(m_stream, "{\"type\":\"FeatureCollection\",\"features\":[\n"); } m_committed_size = m_stream.GetSize(); } void ExportFormatJSON::flush_to_output() { osmium::io::detail::reliable_write(m_fd, m_stream.GetString(), m_stream.GetSize()); m_stream.Clear(); m_committed_size = 0; } void ExportFormatJSON::start_feature(const std::string& prefix, osmium::object_id_type id) { rollback_uncomitted(); if (m_count > 0) { if (!m_text_sequence_format) { m_stream.Put(','); } m_stream.Put('\n'); } m_writer.Reset(m_stream); if (m_with_record_separator) { m_stream.Put(0x1e); } m_writer.StartObject(); // start feature m_writer.Key("type"); m_writer.String("Feature"); if (options().unique_id == unique_id_type::counter) { m_writer.Key("id"); m_writer.Int64(m_count + 1); } else if (options().unique_id == unique_id_type::type_id) { m_writer.Key("id"); m_writer.String(prefix + std::to_string(id)); } } void ExportFormatJSON::add_attributes(const osmium::OSMObject& object) { if (!options().type.empty()) { m_writer.String(options().type); if (object.type() == osmium::item_type::area) { if (static_cast(object).from_way()) { m_writer.String("way"); } else { m_writer.String("relation"); } } else { m_writer.String(osmium::item_type_to_name(object.type())); } } if (!options().id.empty()) { m_writer.String(options().id); m_writer.Int64(object.type() == osmium::item_type::area ? osmium::area_id_to_object_id(object.id()) : object.id()); } if (!options().version.empty()) { m_writer.String(options().version); m_writer.Int(object.version()); } if (!options().changeset.empty()) { m_writer.String(options().changeset); m_writer.Int(object.changeset()); } if (!options().uid.empty()) { m_writer.String(options().uid); m_writer.Int(object.uid()); } if (!options().user.empty()) { m_writer.String(options().user); m_writer.String(object.user()); } if (!options().timestamp.empty()) { m_writer.String(options().timestamp); m_writer.Int(object.timestamp().seconds_since_epoch()); } if (!options().way_nodes.empty() && object.type() == osmium::item_type::way) { m_writer.String(options().way_nodes); m_writer.StartArray(); for (const auto& nr : static_cast(object).nodes()) { m_writer.Int64(nr.ref()); } m_writer.EndArray(); } } bool ExportFormatJSON::add_tags(const osmium::OSMObject& object) { bool has_tags = false; for (const auto& tag : object.tags()) { if (options().tags_filter(tag)) { has_tags = true; m_writer.String(tag.key()); m_writer.String(tag.value()); } } return has_tags; } void ExportFormatJSON::finish_feature(const osmium::OSMObject& object) { m_writer.Key("properties"); m_writer.StartObject(); // start properties add_attributes(object); if (add_tags(object) || options().keep_untagged) { m_writer.EndObject(); // end properties m_writer.EndObject(); // end feature m_committed_size = m_stream.GetSize(); ++m_count; if (m_stream.GetSize() > flush_buffer_size) { flush_to_output(); } } } void ExportFormatJSON::node(const osmium::Node& node) { start_feature("n", node.id()); m_factory.create_point(node); finish_feature(node); } void ExportFormatJSON::way(const osmium::Way& way) { start_feature("w", way.id()); m_factory.create_linestring(way); finish_feature(way); } void ExportFormatJSON::area(const osmium::Area& area) { start_feature("a", area.id()); m_factory.create_multipolygon(area); finish_feature(area); } void ExportFormatJSON::rollback_uncomitted() { const auto uncommitted_size = m_stream.GetSize() - m_committed_size; if (uncommitted_size != 0) { m_stream.Pop(uncommitted_size); } } void ExportFormatJSON::close() { if (m_fd > 0) { rollback_uncomitted(); add_to_stream(m_stream, "\n"); if (!m_text_sequence_format) { add_to_stream(m_stream, "]}\n"); } flush_to_output(); if (m_fsync == osmium::io::fsync::yes) { osmium::io::detail::reliable_fsync(m_fd); } ::close(m_fd); m_fd = -1; } } osmium-tool-1.7.1/src/export/export_format_json.hpp000066400000000000000000000047001315004223400225420ustar00rootroot00000000000000#ifndef EXPORT_JSON_HANDLER #define EXPORT_JSON_HANDLER /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #ifndef RAPIDJSON_HAS_STDSTRING # define RAPIDJSON_HAS_STDSTRING 1 #endif #include #include #pragma GCC diagnostic pop #include #include #include #include "export_format.hpp" using writer_type = rapidjson::Writer; class ExportFormatJSON : public ExportFormat { int m_fd; osmium::io::fsync m_fsync; bool m_text_sequence_format; bool m_with_record_separator; rapidjson::StringBuffer m_stream; std::size_t m_committed_size; writer_type m_writer; osmium::geom::RapidGeoJSONFactory m_factory; void flush_to_output(); void rollback_uncomitted(); void start_feature(const std::string& prefix, osmium::object_id_type id); void add_attributes(const osmium::OSMObject& object); bool add_tags(const osmium::OSMObject& object); void finish_feature(const osmium::OSMObject& object); public: ExportFormatJSON(const std::string& output_format, const std::string& output_filename, osmium::io::overwrite overwrite, osmium::io::fsync fsync, const options_type& options); ~ExportFormatJSON() override { close(); } void node(const osmium::Node& node) override; void way(const osmium::Way& way) override; void area(const osmium::Area& area) override; void close() override; }; // class ExportFormatJSON #endif // EXPORT_JSON_HANDLER osmium-tool-1.7.1/src/export/export_format_text.cpp000066400000000000000000000142671315004223400225610ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "export_format_text.hpp" static constexpr const std::size_t initial_buffer_size = 1024 * 1024; static constexpr const std::size_t flush_buffer_size = 800 * 1024; ExportFormatText::ExportFormatText(const std::string& /*output_format*/, const std::string& output_filename, osmium::io::overwrite overwrite, osmium::io::fsync fsync, const options_type& options) : ExportFormat(options), m_factory(), m_buffer(), m_commit_size(0), m_fd(osmium::io::detail::open_for_writing(output_filename, overwrite)), m_fsync(fsync) { m_buffer.reserve(initial_buffer_size); } void ExportFormatText::flush_to_output() { osmium::io::detail::reliable_write(m_fd, m_buffer.data(), m_buffer.size()); m_buffer.clear(); m_commit_size = 0; } void ExportFormatText::start_feature(char type, osmium::object_id_type id) { m_buffer.resize(m_commit_size); if (options().unique_id == unique_id_type::counter) { m_buffer.append(std::to_string(m_count + 1)); m_buffer.append(1, ' '); } else if (options().unique_id == unique_id_type::type_id) { m_buffer.append(1, type); m_buffer.append(std::to_string(id)); m_buffer.append(1, ' '); } } void ExportFormatText::add_attributes(const osmium::OSMObject& object) { if (!options().type.empty()) { m_buffer.append(options().type); m_buffer.append(1, '='); if (object.type() == osmium::item_type::area) { if (static_cast(object).from_way()) { m_buffer.append("way"); } else { m_buffer.append("relation"); } } else { m_buffer.append(osmium::item_type_to_name(object.type())); } m_buffer.append(1, ','); } if (!options().id.empty()) { m_buffer.append(options().id); m_buffer.append(1, '='); m_buffer.append(std::to_string(object.type() == osmium::item_type::area ? osmium::area_id_to_object_id(object.id()) : object.id())); m_buffer.append(1, ','); } if (!options().version.empty()) { m_buffer.append(options().version); m_buffer.append(1, '='); m_buffer.append(std::to_string(object.version())); m_buffer.append(1, ','); } if (!options().changeset.empty()) { m_buffer.append(options().changeset); m_buffer.append(1, '='); m_buffer.append(std::to_string(object.changeset())); m_buffer.append(1, ','); } if (!options().uid.empty()) { m_buffer.append(options().uid); m_buffer.append(1, '='); m_buffer.append(std::to_string(object.uid())); m_buffer.append(1, ','); } if (!options().user.empty()) { m_buffer.append(options().user); m_buffer.append(1, '='); m_buffer.append(object.user()); m_buffer.append(1, ','); } if (!options().timestamp.empty()) { m_buffer.append(options().timestamp); m_buffer.append(1, '='); m_buffer.append(std::to_string(object.timestamp().seconds_since_epoch())); m_buffer.append(1, ','); } if (!options().way_nodes.empty() && object.type() == osmium::item_type::way) { m_buffer.append(options().way_nodes); m_buffer.append(1, '='); for (const auto& nr : static_cast(object).nodes()) { m_buffer.append(std::to_string(nr.ref())); m_buffer.append(1, '/'); } if (m_buffer.back() == '/') { m_buffer.resize(m_buffer.size() - 1); } } } bool ExportFormatText::add_tags(const osmium::OSMObject& object) { bool has_tags = false; for (const auto& tag : object.tags()) { if (options().tags_filter(tag)) { has_tags = true; osmium::io::detail::append_utf8_encoded_string(m_buffer, tag.key()); m_buffer.append(1, '='); osmium::io::detail::append_utf8_encoded_string(m_buffer, tag.value()); m_buffer.append(1, ','); } } return has_tags; } void ExportFormatText::finish_feature(const osmium::OSMObject& object) { m_buffer.append(1, ' '); add_attributes(object); if (add_tags(object) || options().keep_untagged) { if (m_buffer.back() == ',') { m_buffer.back() = '\n'; } else { m_buffer.append(1, '\n'); } m_commit_size = m_buffer.size(); ++m_count; if (m_buffer.size() > flush_buffer_size) { flush_to_output(); } } } void ExportFormatText::node(const osmium::Node& node) { start_feature('n', node.id()); m_buffer.append(m_factory.create_point(node)); finish_feature(node); } void ExportFormatText::way(const osmium::Way& way) { start_feature('w', way.id()); m_buffer.append(m_factory.create_linestring(way)); finish_feature(way); } void ExportFormatText::area(const osmium::Area& area) { start_feature('a', area.id()); m_buffer.append(m_factory.create_multipolygon(area)); finish_feature(area); } void ExportFormatText::close() { if (m_fd > 0) { flush_to_output(); if (m_fsync == osmium::io::fsync::yes) { osmium::io::detail::reliable_fsync(m_fd); } ::close(m_fd); m_fd = -1; } } osmium-tool-1.7.1/src/export/export_format_text.hpp000066400000000000000000000037161315004223400225630ustar00rootroot00000000000000#ifndef EXPORT_TEXT_HANDLER #define EXPORT_TEXT_HANDLER /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "export_format.hpp" class ExportFormatText : public ExportFormat { osmium::geom::WKTFactory<> m_factory; std::string m_buffer; std::size_t m_commit_size; int m_fd; osmium::io::fsync m_fsync; void flush_to_output(); void start_feature(char type, osmium::object_id_type id); void add_attributes(const osmium::OSMObject& object); bool add_tags(const osmium::OSMObject& object); void finish_feature(const osmium::OSMObject& object); public: ExportFormatText(const std::string& output_format, const std::string& output_filename, osmium::io::overwrite overwrite, osmium::io::fsync fsync, const options_type& options); ~ExportFormatText() override { close(); } void node(const osmium::Node& node) override; void way(const osmium::Way& way) override; void area(const osmium::Area& area) override; void close() override; }; // class ExportFormatText #endif // EXPORT_TEXT_HANDLER osmium-tool-1.7.1/src/export/export_handler.cpp000066400000000000000000000072221315004223400216330ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "../exception.hpp" #include "../util.hpp" #include "export_handler.hpp" static bool check_filter(const osmium::TagList& tags, const char* area_tag_value, const osmium::TagsFilter& filter) noexcept { const char* area_tag = tags.get_value_by_key("area"); if (area_tag) { // has "area" tag and check that it does NOT have the area_tag_value return std::strcmp(area_tag, area_tag_value); } return osmium::tags::match_any_of(tags, filter); } bool ExportHandler::is_linear(const osmium::Way& way) const noexcept { return check_filter(way.tags(), "yes", m_linear_filter); } bool ExportHandler::is_area(const osmium::Area& area) const noexcept { return check_filter(area.tags(), "no", m_area_filter); } ExportHandler::ExportHandler(std::unique_ptr&& handler, const std::vector& linear_tags, const std::vector& area_tags, bool show_errors, bool stop_on_error) : m_handler(std::move(handler)), m_linear_filter(true), m_area_filter(true), m_show_errors(show_errors), m_stop_on_error(stop_on_error) { if (!linear_tags.empty()) { initialize_tags_filter(m_linear_filter, false, linear_tags); } if (!area_tags.empty()) { initialize_tags_filter(m_area_filter, false, area_tags); } } void ExportHandler::show_error(const std::runtime_error& error) { if (m_stop_on_error) { throw; } ++m_error_count; if (m_show_errors) { std::cerr << "Geometry error: " << error.what() << '\n'; } } void ExportHandler::node(const osmium::Node& node) { if (node.tags().empty() && !m_handler->options().keep_untagged) { return; } try { m_handler->node(node); } catch (const osmium::geometry_error& e) { show_error(e); } catch (const osmium::invalid_location& e) { show_error(e); } } void ExportHandler::way(const osmium::Way& way) { if (way.nodes().size() <= 1) { return; } if (!way.is_closed() || is_linear(way)) { try { m_handler->way(way); } catch (const osmium::geometry_error& e) { show_error(e); } catch (const osmium::invalid_location& e) { show_error(e); } } } void ExportHandler::area(const osmium::Area& area) { if (!area.from_way() || is_area(area)) { try { m_handler->area(area); } catch (const osmium::geometry_error& e) { show_error(e); } catch (const osmium::invalid_location& e) { show_error(e); } } } osmium-tool-1.7.1/src/export/export_handler.hpp000066400000000000000000000043031315004223400216350ustar00rootroot00000000000000#ifndef EXPORT_EXPORT_HANDLER_HPP #define EXPORT_EXPORT_HANDLER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include "export_format.hpp" class ExportHandler : public osmium::handler::Handler { std::unique_ptr m_handler; osmium::TagsFilter m_linear_filter; osmium::TagsFilter m_area_filter; uint64_t m_error_count = 0; bool m_show_errors; bool m_stop_on_error; bool is_linear(const osmium::Way& way) const noexcept; bool is_area(const osmium::Area& area) const noexcept; void show_error(const std::runtime_error& error); public: ExportHandler(std::unique_ptr&& handler, const std::vector& linear_tags, const std::vector& area_tags, bool show_errors, bool stop_on_error); void node(const osmium::Node& node); void way(const osmium::Way& way); void area(const osmium::Area& area); void close() const { m_handler->close(); } std::uint64_t count() const noexcept { return m_handler->count(); } std::uint64_t error_count() const noexcept { return m_error_count; } }; // class ExportHandler #endif // EXPORT_EXPORT_HANDLER_HPP osmium-tool-1.7.1/src/export/options.hpp000066400000000000000000000025461315004223400203210ustar00rootroot00000000000000#ifndef EXPORT_OPTIONS_HPP #define EXPORT_OPTIONS_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include enum class unique_id_type { none = 0, counter = 1, type_id = 2 }; struct options_type { osmium::TagsFilter tags_filter{true}; std::string type; std::string id; std::string version; std::string changeset; std::string timestamp; std::string uid; std::string user; std::string way_nodes; unique_id_type unique_id = unique_id_type::none; bool keep_untagged = false; bool print_record_separator = true; }; #endif // EXPORT_OPTIONS_HPP osmium-tool-1.7.1/src/extract/000077500000000000000000000000001315004223400162375ustar00rootroot00000000000000osmium-tool-1.7.1/src/extract/extract.cpp000066400000000000000000000027311315004223400204200ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "extract.hpp" namespace osmium { namespace io { class Header; } namespace memory { class Item; } } void Extract::open_file(const osmium::io::Header& header, osmium::io::overwrite output_overwrite, osmium::io::fsync sync) { m_writer.reset(new osmium::io::Writer{m_output_file, header, output_overwrite, sync}); } void Extract::close_file() { if (m_writer) { m_writer->close(); } } void Extract::write(const osmium::memory::Item& item) { (*m_writer)(item); } std::string Extract::envelope_as_text() const { std::stringstream ss; ss << m_envelope; return ss.str(); } osmium-tool-1.7.1/src/extract/extract.hpp000066400000000000000000000055661315004223400204360ustar00rootroot00000000000000#ifndef EXTRACT_EXTRACT_HPP #define EXTRACT_EXTRACT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include namespace osmium { class Box; class Location; namespace io { class Header; } namespace memory { class Item; } } class Extract { osmium::io::File m_output_file; std::string m_description; std::vector> m_header_options; osmium::Box m_envelope; std::unique_ptr m_writer; public: Extract(const osmium::io::File& output_file, const std::string& description, const osmium::Box& envelope) : m_output_file(output_file), m_description(description), m_envelope(envelope), m_writer(nullptr) { } virtual ~Extract() = default; const std::string& output() const noexcept { return m_output_file.filename(); } const char* output_format() const noexcept { return osmium::io::as_string(m_output_file.format()); } const std::string& description() const noexcept { return m_description; } const osmium::Box& envelope() const noexcept { return m_envelope; } void add_header_option(const std::string& name, const std::string& value) { m_header_options.emplace_back(name, value); } const std::vector>& header_options() const noexcept { return m_header_options; } osmium::io::Writer& writer() { return *m_writer; } void open_file(const osmium::io::Header& header, osmium::io::overwrite output_overwrite, osmium::io::fsync sync); void close_file(); void write(const osmium::memory::Item& item); std::string envelope_as_text() const; virtual bool contains(const osmium::Location& location) const noexcept = 0; virtual const char* geometry_type() const noexcept = 0; virtual std::string geometry_as_text() const = 0; }; // class Extract #endif // EXTRACT_EXTRACT_HPP osmium-tool-1.7.1/src/extract/extract_bbox.cpp000066400000000000000000000024701315004223400214320ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "extract_bbox.hpp" bool ExtractBBox::contains(const osmium::Location& location) const noexcept { return location.valid() && envelope().contains(location); } const char* ExtractBBox::geometry_type() const noexcept { return "bbox"; } std::string ExtractBBox::geometry_as_text() const { std::string s{"BOX("}; envelope().bottom_left().as_string(std::back_inserter(s), ' '); s += ','; envelope().top_right().as_string(std::back_inserter(s), ' '); s += ')'; return s; } osmium-tool-1.7.1/src/extract/extract_bbox.hpp000066400000000000000000000024761315004223400214450ustar00rootroot00000000000000#ifndef EXTRACT_EXTRACT_BBOX_HPP #define EXTRACT_EXTRACT_BBOX_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "extract.hpp" class ExtractBBox : public Extract { public: ExtractBBox(const osmium::io::File& output_file, const std::string& description, const osmium::Box& box) : Extract(output_file, description, box) { } bool contains(const osmium::Location& location) const noexcept override final; const char* geometry_type() const noexcept override final; std::string geometry_as_text() const override final; }; // class ExtractBBox #endif // EXTRACT_EXTRACT_BBOX_HPP osmium-tool-1.7.1/src/extract/extract_polygon.cpp000066400000000000000000000117061315004223400221710ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "extract_polygon.hpp" static void add_ring(std::vector& segments, const osmium::NodeRefList& ring) { auto it = ring.begin(); const auto end = ring.end(); assert(it != end); auto last_it = it++; while (it != end) { segments.emplace_back(last_it->location(), it->location()); last_it = it++; } } const osmium::Area& ExtractPolygon::area() const noexcept { return m_buffer.get(m_offset); } ExtractPolygon::ExtractPolygon(const osmium::io::File& output_file, const std::string& description, const osmium::memory::Buffer& buffer, std::size_t offset) : Extract(output_file, description, buffer.get(offset).envelope()), m_buffer(buffer), m_offset(offset), m_bands(), m_dy(0) { // get segments from all rings std::vector segments; for (const auto& outer_ring : area().outer_rings()) { add_ring(segments, outer_ring); for (const auto& inner_ring : area().inner_rings(outer_ring)) { add_ring(segments, inner_ring); } } // split y range into equal-sized bands constexpr const int32_t segments_per_band = 10; constexpr const int32_t max_bands = 10000; int32_t num_bands = static_cast(segments.size()) / segments_per_band; if (num_bands < 1) { num_bands = 1; } else if (num_bands > max_bands) { num_bands = max_bands; } m_bands.resize(num_bands); m_dy = (y_max() - y_min()) / num_bands; // put segments into the bands they overlap for (const auto& segment : segments) { const std::pair mm = std::minmax(segment.first().y(), segment.second().y()); const uint32_t band_min = (mm.first - y_min()) / m_dy; const uint32_t band_max = std::min(num_bands, ((mm.second - y_min()) / m_dy) + 1); for (auto band = band_min; band < band_max; ++band) { m_bands[band].push_back(segment); } } } /* Simple point-in-polygon algorithm adapted from https://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy) { int i, j, c = 0; for (i = 0, j = nvert-1; i < nvert; j = i++) { if ( ((verty[i]>testy) != (verty[j]>testy)) && (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) ) c = !c; } return c; } In our implementation we split the y-range into equal-sized subranges and only have to test all segments in the subrange that contains the y coordinate of the node. */ bool ExtractPolygon::contains(const osmium::Location& location) const noexcept { if (!location.valid() || ! envelope().contains(location)) { return false; } std::size_t band = (location.y() - y_min()) / m_dy; if (band >= m_bands.size()) { band = m_bands.size() - 1; } bool inside = false; for (const auto& segment : m_bands[band]) { if (segment.first() == location || segment.second() == location) { return true; } if ((segment.second().y() > location.y()) != (segment.first().y() > location.y())) { const int64_t ax = int64_t(segment.first().x()) - int64_t(segment.second().x()); const int64_t ay = int64_t(segment.first().y()) - int64_t(segment.second().y()); const int64_t tx = int64_t(location.x()) - int64_t(segment.second().x()); const int64_t ty = int64_t(location.y()) - int64_t(segment.second().y()); const bool comp = tx * ay < ax * ty; if ((ay > 0) == comp) { inside = !inside; } } } return inside; } const char* ExtractPolygon::geometry_type() const noexcept { return "polygon"; } std::string ExtractPolygon::geometry_as_text() const { osmium::geom::WKTFactory<> factory; return factory.create_multipolygon(area()); } osmium-tool-1.7.1/src/extract/extract_polygon.hpp000066400000000000000000000033671315004223400222020ustar00rootroot00000000000000#ifndef EXTRACT_EXTRACT_POLYGON_HPP #define EXTRACT_EXTRACT_POLYGON_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "extract.hpp" namespace osmium { class Area; class Segment; } class ExtractPolygon : public Extract { const osmium::memory::Buffer& m_buffer; std::size_t m_offset; std::vector> m_bands; int32_t m_dy; const osmium::Area& area() const noexcept; int32_t y_max() const noexcept { return envelope().top_right().y(); } int32_t y_min() const noexcept { return envelope().bottom_left().y(); } public: ExtractPolygon(const osmium::io::File& output_file, const std::string& description, const osmium::memory::Buffer& buffer, std::size_t offset); bool contains(const osmium::Location& location) const noexcept override final; const char* geometry_type() const noexcept override final; std::string geometry_as_text() const override final; }; // class ExtractPolygon #endif // EXTRACT_EXTRACT_POLYGON_HPP osmium-tool-1.7.1/src/extract/geojson_file_parser.cpp000066400000000000000000000151251315004223400227660ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include "../exception.hpp" #include "geojson_file_parser.hpp" std::string get_value_as_string(const rapidjson::Value& object, const char* key) { assert(object.IsObject()); const auto it = object.FindMember(key); if (it == object.MemberEnd()) { return ""; } if (it->value.IsString()) { return it->value.GetString(); } else { throw config_error{std::string{"Value for name '"} + key + "' must be a string."}; } } // parse coordinate pair from JSON array osmium::geom::Coordinates parse_coordinate(const rapidjson::Value& value) { if (!value.IsArray()) { throw config_error{"Coordinates must be an array."}; } const auto array = value.GetArray(); if (array.Size() != 2) { throw config_error{"Coordinates array must have exactly two elements."}; } if (array[0].IsNumber() && array[1].IsNumber()) { return osmium::geom::Coordinates{array[0].GetDouble(), array[1].GetDouble()}; } throw config_error{"Coordinates array must contain numbers."}; } std::vector parse_ring(const rapidjson::Value& value) { if (!value.IsArray()) { throw config_error{"Ring must be an array."}; } const auto array = value.GetArray(); if (array.Size() < 3) { throw config_error{"Ring must contain at least three coordinate pairs."}; } std::vector coordinates; for (const rapidjson::Value& item : array) { coordinates.push_back(parse_coordinate(item)); } return coordinates; } void parse_rings(const rapidjson::Value& value, osmium::builder::AreaBuilder& builder) { assert(value.IsArray()); const auto array = value.GetArray(); if (array.Size() < 1) { throw config_error{"Polygon must contain at least one ring."}; } { const auto outer_ring = parse_ring(array[0]); osmium::builder::OuterRingBuilder ring_builder{builder}; for (const auto& c : outer_ring) { ring_builder.add_node_ref(0, osmium::Location{c.x, c.y}); } } for (unsigned int i = 1; i < array.Size(); ++i) { const auto inner_ring = parse_ring(array[i]); osmium::builder::InnerRingBuilder ring_builder{builder}; for (const auto& c : inner_ring) { ring_builder.add_node_ref(0, osmium::Location{c.x, c.y}); } } } std::size_t parse_polygon_array(const rapidjson::Value& value, osmium::memory::Buffer& buffer) { { osmium::builder::AreaBuilder builder{buffer}; parse_rings(value, builder); } return buffer.commit(); } std::size_t parse_multipolygon_array(const rapidjson::Value& value, osmium::memory::Buffer& buffer) { assert(value.IsArray()); const auto array = value.GetArray(); if (array.Size() < 1) { throw config_error{"Multipolygon must contain at least one polygon array."}; } { osmium::builder::AreaBuilder builder{buffer}; for (const auto& polygon : array) { if (!polygon.IsArray()) { throw config_error{"Polygon must be an array."}; } parse_rings(polygon, builder); } } return buffer.commit(); } void GeoJSONFileParser::error(const std::string& message) { throw geojson_error{std::string{"In file '"} + m_file_name + "':\n" + message}; } GeoJSONFileParser::GeoJSONFileParser(osmium::memory::Buffer& buffer, const std::string& file_name) : m_buffer(buffer), m_file_name(file_name), m_file(m_file_name) { if (!m_file.is_open()) { throw config_error{std::string{"Could not open file '"} + m_file_name + "'."}; } } std::size_t GeoJSONFileParser::operator()() { rapidjson::IStreamWrapper stream_wrapper{m_file}; rapidjson::Document doc; if (doc.ParseStream(stream_wrapper).HasParseError()) { error(std::string{"JSON error at offset "} + std::to_string(doc.GetErrorOffset()) + " : " + rapidjson::GetParseError_En(doc.GetParseError())); } if (!doc.IsObject()) { error("Top-level value must be an object."); } const std::string type{get_value_as_string(doc, "type")}; if (type.empty()) { error("Expected 'type' name with the value 'Feature'."); } if (type != "Feature") { error("Expected 'type' value to be 'Feature'."); } const auto json_geometry = doc.FindMember("geometry"); if (json_geometry == doc.MemberEnd()) { error("Missing 'geometry' name."); } if (!json_geometry->value.IsObject()) { error("Expected 'geometry' value to be an object."); } std::string geometry_type{get_value_as_string(json_geometry->value, "type")}; if (geometry_type.empty()) { error("Missing 'geometry.type'."); } if (geometry_type != "Polygon" && geometry_type != "MultiPolygon") { error("Expected 'geometry.type' value to be 'Polygon' or 'MultiPolygon'."); } const auto json_coordinates = json_geometry->value.FindMember("coordinates"); if (json_coordinates == json_geometry->value.MemberEnd()) { error("Missing 'coordinates' name in 'geometry' object."); } if (!json_coordinates->value.IsArray()) { error("Expected 'geometry.coordinates' value to be an array."); } if (geometry_type == "Polygon") { return parse_polygon_array(json_coordinates->value, m_buffer); } else { return parse_multipolygon_array(json_coordinates->value, m_buffer); } } osmium-tool-1.7.1/src/extract/geojson_file_parser.hpp000066400000000000000000000032021315004223400227640ustar00rootroot00000000000000#ifndef EXTRACT_GEOJSON_FILE_PARSER_HPP #define EXTRACT_GEOJSON_FILE_PARSER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include namespace osmium { namespace memory { class Buffer; }} std::string get_value_as_string(const rapidjson::Value& object, const char* key); std::size_t parse_polygon_array(const rapidjson::Value& value, osmium::memory::Buffer& buffer); std::size_t parse_multipolygon_array(const rapidjson::Value& value, osmium::memory::Buffer& buffer); /** * Gets areas from OSM files. */ class GeoJSONFileParser { osmium::memory::Buffer& m_buffer; std::string m_file_name; std::ifstream m_file; void error(const std::string& message); public: GeoJSONFileParser(osmium::memory::Buffer& buffer, const std::string& file_name); std::size_t operator()(); }; // class GeoJSONFileParser #endif // EXTRACT_GEOJSON_FILE_PARSER_HPP osmium-tool-1.7.1/src/extract/osm_file_parser.cpp000066400000000000000000000054341315004223400221220ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "osm_file_parser.hpp" using index_type = osmium::index::map::SparseMemArray; using location_handler_type = osmium::handler::NodeLocationsForWays; OSMFileParser::OSMFileParser(osmium::memory::Buffer& buffer, const std::string& file_name) : m_buffer(buffer), m_file_name(file_name) { } std::size_t OSMFileParser::operator()() { osmium::io::File input_file{m_file_name}; osmium::area::Assembler::config_type assembler_config; osmium::area::MultipolygonCollector collector{assembler_config}; { osmium::io::Reader reader{input_file, osmium::osm_entity_bits::relation}; collector.read_relations(reader); reader.close(); } bool has_ring = false; { index_type index; location_handler_type location_handler{index}; osmium::builder::AreaBuilder builder{m_buffer}; osmium::io::Reader reader{input_file}; osmium::apply(reader, location_handler, collector.handler([&](osmium::memory::Buffer&& buffer) { for (const auto& area : buffer.select()) { for (const auto& item : area) { if (item.type() == osmium::item_type::outer_ring || item.type() == osmium::item_type::inner_ring) { builder.add_item(item); has_ring = true; } } } })); reader.close(); } if (has_ring) { return m_buffer.commit(); } m_buffer.rollback(); throw osmium::io_error{"No areas found in the OSM file."}; } osmium-tool-1.7.1/src/extract/osm_file_parser.hpp000066400000000000000000000023271315004223400221250ustar00rootroot00000000000000#ifndef EXTRACT_OSM_FILE_PARSER_HPP #define EXTRACT_OSM_FILE_PARSER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include namespace osmium { namespace memory { class Buffer; }} /** * Gets areas from OSM files. */ class OSMFileParser { osmium::memory::Buffer& m_buffer; std::string m_file_name; public: OSMFileParser(osmium::memory::Buffer& buffer, const std::string& file_name); std::size_t operator()(); }; // class OSMFileParser #endif // EXTRACT_OSM_FILE_PARSER_HPP osmium-tool-1.7.1/src/extract/poly_file_parser.cpp000066400000000000000000000074111315004223400223040ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include "../exception.hpp" #include "poly_file_parser.hpp" void PolyFileParser::error(const std::string& message) { throw poly_error{std::string{"In file '"} + m_file_name + "' on line " + std::to_string(m_line + 1) + ":\n" + message}; } PolyFileParser::PolyFileParser(osmium::memory::Buffer& buffer, const std::string& file_name) : m_buffer(buffer), m_builder(nullptr), m_file_name(file_name), m_data() { std::ifstream file{file_name}; if (!file.is_open()) { throw config_error{std::string{"Could not open file '"} + file_name + "'"}; } std::stringstream sstr; sstr << file.rdbuf(); m_data = osmium::split_string(sstr.str(), '\n', true); // remove CR at end of lines for (auto& line : m_data) { if (line.back() == '\r') { line.resize(line.size() - 1); } } } void PolyFileParser::parse_ring() { bool inner_ring = line()[0] == '!'; ++m_line; std::vector coordinates; while (m_line < m_data.size()) { if (line() == "END") { if (coordinates.size() < 3) { error("Expected at least three lines with coordinates."); } if (coordinates.front() != coordinates.back()) { coordinates.push_back(coordinates.front()); } if (inner_ring) { osmium::builder::InnerRingBuilder ring_builder{*m_builder}; for (const auto& location : coordinates) { ring_builder.add_node_ref(0, location); } } else { osmium::builder::OuterRingBuilder ring_builder{*m_builder}; for (const auto& location : coordinates) { ring_builder.add_node_ref(0, location); } } ++m_line; return; } std::istringstream sstr{line()}; double lon, lat; if (!(sstr >> lon >> lat)) { error("Expected coordinates or 'END' to end the ring."); } coordinates.emplace_back(lon, lat); ++m_line; } } void PolyFileParser::parse_multipolygon() { ++m_line; // ignore first line while (m_line < m_data.size()) { if (line() == "END") { ++m_line; if (m_line == 2) { error("Need at least one ring in (multi)polygon."); } return; } parse_ring(); } --m_line; error("Expected 'END' for end of (multi)polygon."); } std::size_t PolyFileParser::operator()() { if (m_data.empty()) { throw poly_error{std::string{"File '"} + m_file_name + "' is empty."}; } m_builder.reset(new osmium::builder::AreaBuilder{m_buffer}); while (m_line < m_data.size()) { parse_multipolygon(); } m_builder.reset(); return m_buffer.commit(); } osmium-tool-1.7.1/src/extract/poly_file_parser.hpp000066400000000000000000000037011315004223400223070ustar00rootroot00000000000000#ifndef EXTRACT_POLY_FILE_PARSER_HPP #define EXTRACT_POLY_FILE_PARSER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include namespace osmium { namespace memory { class Buffer; }} /** * Thrown when there is a problem with parsing a poly file. */ struct poly_error : public std::runtime_error { explicit poly_error(const std::string& message) : std::runtime_error(message) { } }; // struct poly_error /** * Gets areas from .poly files. * * Format description: * http://wiki.openstreetmap.org/wiki/Osmosis/Polygon_Filter_File_Format */ class PolyFileParser { osmium::memory::Buffer& m_buffer; std::unique_ptr m_builder; std::string m_file_name; std::vector m_data; std::size_t m_line = 0; void parse_ring(); void parse_multipolygon(); const std::string& line() const noexcept { return m_data[m_line]; } void error(const std::string& message); public: PolyFileParser(osmium::memory::Buffer& buffer, const std::string& file_name); std::size_t operator()(); }; // class PolyFileParser #endif // EXTRACT_POLY_FILE_PARSER_HPP osmium-tool-1.7.1/src/extract/strategy.hpp000066400000000000000000000110401315004223400206060ustar00rootroot00000000000000#ifndef EXTRACT_STRATEGY_HPP #define EXTRACT_STRATEGY_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "extract.hpp" template class ExtractData : public T { Extract* m_extract_ptr; public: explicit ExtractData(Extract& extract) : T(), m_extract_ptr(&extract) { } bool contains(const osmium::Location& location) const noexcept { return m_extract_ptr->contains(location); } void write(const osmium::memory::Item& item) { m_extract_ptr->write(item); } void close() { m_extract_ptr->close_file(); } }; // class ExtractData class ExtractStrategy { public: ExtractStrategy() = default; virtual ~ExtractStrategy() = default; virtual const char* name() const noexcept = 0; virtual void show_arguments(osmium::util::VerboseOutput& /*vout*/) { } virtual void run(osmium::util::VerboseOutput& vout, bool display_progress, const osmium::io::File& input_file) = 0; }; // class ExtractStrategy template class Pass { TStrategy& m_strategy; void run_impl(osmium::ProgressBar& progress_bar, osmium::io::Reader& reader) { while (osmium::memory::Buffer buffer = reader.read()) { progress_bar.update(reader.offset()); for (const auto& object : buffer) { switch (object.type()) { case osmium::item_type::node: self().node(static_cast(object)); for (auto& e : extracts()) { self().enode(e, static_cast(object)); } break; case osmium::item_type::way: self().way(static_cast(object)); for (auto& e : extracts()) { self().eway(e, static_cast(object)); } break; case osmium::item_type::relation: self().relation(static_cast(object)); for (auto& e : extracts()) { self().erelation(e, static_cast(object)); } break; default: break; } } } } protected: using extract_data = typename TStrategy::extract_data; TStrategy& strategy() { return m_strategy; } std::vector& extracts() { return m_strategy.m_extracts; } TChild& self() { return *static_cast(this); } void node(const osmium::Node&) { } void way(const osmium::Way&) { } void relation(const osmium::Relation&) { } void enode(extract_data&, const osmium::Node&) { } void eway(extract_data&, const osmium::Way&) { } void erelation(extract_data&, const osmium::Relation&) { } public: explicit Pass(TStrategy& strategy) : m_strategy(strategy) { } template void run(osmium::ProgressBar& progress_bar, Args ...args) { osmium::io::Reader reader{std::forward(args)...}; run_impl(progress_bar, reader); reader.close(); } }; // class Pass #endif // EXTRACT_STRATEGY_HPP osmium-tool-1.7.1/src/extract/strategy_complete_ways.cpp000066400000000000000000000135401315004223400235430ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "strategy_complete_ways.hpp" #include "../util.hpp" namespace strategy_complete_ways { void Data::add_relation_parents(osmium::unsigned_object_id_type id, const osmium::index::RelationsMapIndex& map) { map.for_each_parent(id, [&](osmium::unsigned_object_id_type parent_id) { if (! relation_ids.get(parent_id)) { relation_ids.set(parent_id); add_relation_parents(parent_id, map); } }); } Strategy::Strategy(const std::vector>& extracts, const osmium::util::Options& options) : ExtractStrategy() { m_extracts.reserve(extracts.size()); for (const auto& extract : extracts) { m_extracts.emplace_back(*extract); } for (const auto& option : options) { warning(std::string{"Ignoring unknown option '"} + option.first + "' for 'complete_ways' strategy.\n"); } } const char* Strategy::name() const noexcept { return "complete_ways"; } class Pass1 : public Pass { osmium::handler::CheckOrder m_check_order; osmium::index::RelationsMapStash m_relations_map_stash; public: Pass1(Strategy& strategy) : Pass(strategy) { } void node(const osmium::Node& node) { m_check_order.node(node); } void enode(extract_data& e, const osmium::Node& node) { if (e.contains(node.location())) { e.node_ids.set(node.positive_id()); } } void way(const osmium::Way& way) { m_check_order.way(way); } void eway(extract_data& e, const osmium::Way& way) { for (const auto& nr : way.nodes()) { if (e.node_ids.get(nr.positive_ref())) { e.way_ids.set(way.positive_id()); for (const auto& nr : way.nodes()) { e.extra_node_ids.set(nr.ref()); } return; } } } void relation(const osmium::Relation& relation) { m_check_order.relation(relation); m_relations_map_stash.add_members(relation); } void erelation(extract_data& e, const osmium::Relation& relation) { for (const auto& member : relation.members()) { switch (member.type()) { case osmium::item_type::node: if (e.node_ids.get(member.positive_ref())) { e.relation_ids.set(relation.positive_id()); return; } break; case osmium::item_type::way: if (e.way_ids.get(member.positive_ref())) { e.relation_ids.set(relation.positive_id()); return; } break; default: break; } } } osmium::index::RelationsMapStash& relations_map_stash() noexcept { return m_relations_map_stash; } }; // class Pass1 class Pass2 : public Pass { public: Pass2(Strategy& strategy) : Pass(strategy) { } void enode(extract_data& e, const osmium::Node& node) { if (e.node_ids.get(node.positive_id()) || e.extra_node_ids.get(node.positive_id())) { e.write(node); } } void eway(extract_data& e, const osmium::Way& way) { if (e.way_ids.get(way.positive_id())) { e.write(way); } } void erelation(extract_data& e, const osmium::Relation& relation) { if (e.relation_ids.get(relation.positive_id())) { e.write(relation); } } }; // class Pass2 void Strategy::run(osmium::util::VerboseOutput& vout, bool display_progress, const osmium::io::File& input_file) { vout << "Running 'complete_ways' strategy in two passes...\n"; const std::size_t file_size = osmium::util::file_size(input_file.filename()); osmium::ProgressBar progress_bar{file_size * 2, display_progress}; vout << "First pass...\n"; Pass1 pass1{*this}; pass1.run(progress_bar, input_file, osmium::io::read_meta::no); progress_bar.file_done(file_size); // recursively get parents of all relations that are in an extract const auto relations_map = pass1.relations_map_stash().build_member_to_parent_index(); for (auto& e : m_extracts) { for (osmium::unsigned_object_id_type id : e.relation_ids) { e.add_relation_parents(id, relations_map); } } progress_bar.remove(); vout << "Second pass...\n"; Pass2 pass2{*this}; pass2.run(progress_bar, input_file); progress_bar.done(); } } // namespace strategy_complete_ways osmium-tool-1.7.1/src/extract/strategy_complete_ways.hpp000066400000000000000000000041621315004223400235500ustar00rootroot00000000000000#ifndef EXTRACT_STRATEGY_COMPLETE_WAYS_HPP #define EXTRACT_STRATEGY_COMPLETE_WAYS_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "strategy.hpp" namespace strategy_complete_ways { struct Data { osmium::index::IdSetDense node_ids; osmium::index::IdSetDense extra_node_ids; osmium::index::IdSetDense way_ids; osmium::index::IdSetDense relation_ids; void add_relation_parents(osmium::unsigned_object_id_type id, const osmium::index::RelationsMapIndex& map); }; class Strategy : public ExtractStrategy { template friend class ::Pass; friend class Pass1; using extract_data = ExtractData; std::vector m_extracts; public: explicit Strategy(const std::vector>& extracts, const osmium::util::Options& /*options*/); const char* name() const noexcept override final; void run(osmium::util::VerboseOutput& vout, bool display_progress, const osmium::io::File& input_file) override final; }; // class Strategy } // namespace strategy_complete_ways #endif // EXTRACT_STRATEGY_COMPLETE_WAYS_HPP osmium-tool-1.7.1/src/extract/strategy_complete_ways_with_history.cpp000066400000000000000000000141251315004223400263570ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "strategy_complete_ways_with_history.hpp" namespace strategy_complete_ways_with_history { void Data::add_relation_parents(osmium::unsigned_object_id_type id, const osmium::index::RelationsMapIndex& map) { map.for_each_parent(id, [&](osmium::unsigned_object_id_type parent_id) { if (! relation_ids.get(parent_id)) { relation_ids.set(parent_id); add_relation_parents(parent_id, map); } }); } Strategy::Strategy(const std::vector>& extracts, const osmium::util::Options& /*options*/) : ExtractStrategy() { m_extracts.reserve(extracts.size()); for (const auto& extract : extracts) { m_extracts.emplace_back(*extract); } } const char* Strategy::name() const noexcept { return "complete_ways"; } class Pass1 : public Pass { osmium::index::RelationsMapStash m_relations_map_stash; std::vector m_current_way_nodes; osmium::unsigned_object_id_type m_current_way_id = 0; public: Pass1(Strategy& strategy) : Pass(strategy) { } void add_extra_nodes() { for (auto& e : extracts()) { if (e.way_ids.get(m_current_way_id)) { for (const auto& id : m_current_way_nodes) { e.extra_node_ids.set(id); } } } m_current_way_nodes.clear(); } void enode(extract_data& e, const osmium::Node& node) { if (e.contains(node.location())) { e.node_ids.set(node.positive_id()); } } void way(const osmium::Way& way) { if (m_current_way_id != way.positive_id()) { add_extra_nodes(); m_current_way_id = way.id(); } for (const auto& wn : way.nodes()) { m_current_way_nodes.push_back(wn.positive_ref()); } } void eway(extract_data& e, const osmium::Way& way) { for (const auto& nr : way.nodes()) { if (e.node_ids.get(nr.positive_ref())) { e.way_ids.set(way.positive_id()); return; } } } void relation(const osmium::Relation& relation) { m_relations_map_stash.add_members(relation); } void erelation(extract_data& e, const osmium::Relation& relation) { for (const auto& member : relation.members()) { switch (member.type()) { case osmium::item_type::node: if (e.node_ids.get(member.positive_ref())) { e.relation_ids.set(relation.positive_id()); return; } break; case osmium::item_type::way: if (e.way_ids.get(member.positive_ref())) { e.relation_ids.set(relation.positive_id()); return; } break; default: break; } } } osmium::index::RelationsMapStash& relations_map_stash() noexcept { return m_relations_map_stash; } }; // class Pass1 class Pass2 : public Pass { public: Pass2(Strategy& strategy) : Pass(strategy) { } void enode(extract_data& e, const osmium::Node& node) { if (e.node_ids.get(node.positive_id()) || e.extra_node_ids.get(node.positive_id())) { e.write(node); } } void eway(extract_data& e, const osmium::Way& way) { if (e.way_ids.get(way.positive_id())) { e.write(way); } } void erelation(extract_data& e, const osmium::Relation& relation) { if (e.relation_ids.get(relation.positive_id())) { e.write(relation); } } }; // class Pass2 void Strategy::run(osmium::util::VerboseOutput& vout, bool display_progress, const osmium::io::File& input_file) { vout << "Running 'complete_ways' strategy in two passes...\n"; const std::size_t file_size = osmium::util::file_size(input_file.filename()); osmium::ProgressBar progress_bar{file_size * 2, display_progress}; vout << "First pass...\n"; Pass1 pass1{*this}; pass1.run(progress_bar, input_file, osmium::io::read_meta::no); progress_bar.file_done(file_size); pass1.add_extra_nodes(); // recursively get parents of all relations that are in an extract const auto relations_map = pass1.relations_map_stash().build_member_to_parent_index(); for (auto& e : m_extracts) { for (osmium::unsigned_object_id_type id : e.relation_ids) { e.add_relation_parents(id, relations_map); } } progress_bar.remove(); vout << "Second pass...\n"; Pass2 pass2{*this}; pass2.run(progress_bar, input_file); progress_bar.done(); } } // namespace strategy_complete_ways_with_history osmium-tool-1.7.1/src/extract/strategy_complete_ways_with_history.hpp000066400000000000000000000042631315004223400263660ustar00rootroot00000000000000#ifndef EXTRACT_STRATEGY_COMPLETE_WAYS_WITH_HISTORY_HPP #define EXTRACT_STRATEGY_COMPLETE_WAYS_WITH_HISTORY_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "strategy.hpp" namespace strategy_complete_ways_with_history { struct Data { osmium::index::IdSetDense node_ids; osmium::index::IdSetDense extra_node_ids; osmium::index::IdSetDense way_ids; osmium::index::IdSetDense relation_ids; void add_relation_parents(osmium::unsigned_object_id_type id, const osmium::index::RelationsMapIndex& map); }; class Strategy : public ExtractStrategy { template friend class ::Pass; friend class Pass1; using extract_data = ExtractData; std::vector m_extracts; public: explicit Strategy(const std::vector>& extracts, const osmium::util::Options& /*options*/); const char* name() const noexcept override final; void run(osmium::util::VerboseOutput& vout, bool display_progress, const osmium::io::File& input_file) override final; }; // class Strategy } // namespace strategy_complete_ways_with_history #endif // EXTRACT_STRATEGY_COMPLETE_WAYS_WITH_HISTORY_HPP osmium-tool-1.7.1/src/extract/strategy_simple.cpp000066400000000000000000000071751315004223400221700ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "strategy_simple.hpp" #include "../util.hpp" namespace strategy_simple { Strategy::Strategy(const std::vector>& extracts, const osmium::util::Options& options) : ExtractStrategy() { m_extracts.reserve(extracts.size()); for (const auto& extract : extracts) { m_extracts.emplace_back(*extract); } for (const auto& option : options) { warning(std::string{"Ignoring unknown option '"} + option.first + "' for 'simple' strategy.\n"); } } const char* Strategy::name() const noexcept { return "simple"; } class Pass1 : public Pass { osmium::handler::CheckOrder m_check_order; public: Pass1(Strategy& strategy) : Pass(strategy) { } void node(const osmium::Node& node) { m_check_order.node(node); } void enode(extract_data& e, const osmium::Node& node) { if (e.contains(node.location())) { e.write(node); e.node_ids.set(node.positive_id()); } } void way(const osmium::Way& way) { m_check_order.way(way); } void eway(extract_data& e, const osmium::Way& way) { for (const auto& nr : way.nodes()) { if (e.node_ids.get(nr.positive_ref())) { e.write(way); e.way_ids.set(way.positive_id()); } return; } } void relation(const osmium::Relation& relation) { m_check_order.relation(relation); } void erelation(extract_data& e, const osmium::Relation& relation) { for (const auto& member : relation.members()) { switch (member.type()) { case osmium::item_type::node: if (e.node_ids.get(member.positive_ref())) { e.write(relation); } return; case osmium::item_type::way: if (e.way_ids.get(member.positive_ref())) { e.write(relation); } return; default: break; } } } }; // class Pass1 void Strategy::run(osmium::util::VerboseOutput& vout, bool display_progress, const osmium::io::File& input_file) { vout << "Running 'simple' strategy in one pass...\n"; const std::size_t file_size = osmium::util::file_size(input_file.filename()); osmium::ProgressBar progress_bar{file_size, display_progress}; Pass1 pass1{*this}; pass1.run(progress_bar, input_file); progress_bar.done(); } } // namespace strategy_simple osmium-tool-1.7.1/src/extract/strategy_simple.hpp000066400000000000000000000034141315004223400221650ustar00rootroot00000000000000#ifndef EXTRACT_STRATEGY_SIMPLE_HPP #define EXTRACT_STRATEGY_SIMPLE_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "strategy.hpp" namespace strategy_simple { struct Data { osmium::index::IdSetDense node_ids; osmium::index::IdSetDense way_ids; }; class Strategy : public ExtractStrategy { template friend class ::Pass; friend class Pass1; using extract_data = ExtractData; std::vector m_extracts; public: explicit Strategy(const std::vector>& extracts, const osmium::util::Options& /*options*/); const char* name() const noexcept override final; void run(osmium::util::VerboseOutput& vout, bool display_progress, const osmium::io::File& input_file) override final; }; // class Strategy } // namespace strategy_simple #endif // EXTRACT_STRATEGY_SIMPLE_HPP osmium-tool-1.7.1/src/extract/strategy_smart.cpp000066400000000000000000000206621315004223400220210ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "strategy_smart.hpp" #include "../util.hpp" namespace strategy_smart { void Data::add_relation(const osmium::Relation& relation) { for (const auto& member : relation.members()) { const auto ref = member.positive_ref(); switch (member.type()) { case osmium::item_type::node: extra_node_ids.set(ref); break; case osmium::item_type::way: extra_way_ids.set(ref); break; default: break; } } } void Data::add_relation_parents(osmium::unsigned_object_id_type id, const osmium::index::RelationsMapIndex& map) { map.for_each_parent(id, [&](osmium::unsigned_object_id_type parent_id) { if (! relation_ids.get(parent_id) && ! extra_relation_ids.get(parent_id)) { relation_ids.set(parent_id); add_relation_parents(parent_id, map); } }); } Strategy::Strategy(const std::vector>& extracts, const osmium::util::Options& options) : ExtractStrategy(), m_types() { m_extracts.reserve(extracts.size()); for (const auto& extract : extracts) { m_extracts.emplace_back(*extract); } for (const auto& option : options) { if (std::string{"types"} != option.first) { warning(std::string{"Ignoring unknown option '"} + option.first + "' for 'smart' strategy.\n"); } } const auto types = options.get("types"); if (types == "") { m_types = {"multipolygon"}; } else if (types != "any") { m_types = osmium::split_string(types, ',', true); } } const char* Strategy::name() const noexcept { return "smart"; } bool Strategy::check_type(const osmium::Relation& relation) const noexcept { if (m_types.empty()) { return true; } const char* type = relation.tags()["type"]; if (!type) { return false; } const auto it = std::find(m_types.begin(), m_types.end(), type); return it != m_types.end(); } void Strategy::show_arguments(osmium::util::VerboseOutput& vout) { vout << "Additional strategy options:\n"; if (m_types.empty()) { vout << " types: any\n"; } else { vout << " types:\n"; for (const auto& type : m_types) { vout << " " << type << '\n'; } } vout << '\n'; } class Pass1 : public Pass { osmium::handler::CheckOrder m_check_order; osmium::index::RelationsMapStash m_relations_map_stash; public: Pass1(Strategy& strategy) : Pass(strategy) { } void node(const osmium::Node& node) { m_check_order.node(node); } void enode(extract_data& e, const osmium::Node& node) { if (e.contains(node.location())) { e.node_ids.set(node.positive_id()); } } void way(const osmium::Way& way) { m_check_order.way(way); } void eway(extract_data& e, const osmium::Way& way) { for (const auto& nr : way.nodes()) { if (e.node_ids.get(nr.positive_ref())) { e.way_ids.set(way.positive_id()); return; } } } void relation(const osmium::Relation& relation) { m_check_order.relation(relation); m_relations_map_stash.add_members(relation); } void erelation(extract_data& e, const osmium::Relation& relation) { for (const auto& member : relation.members()) { switch (member.type()) { case osmium::item_type::node: if (e.node_ids.get(member.positive_ref())) { e.relation_ids.set(relation.positive_id()); if (strategy().check_type(relation)) { e.add_relation(relation); } return; } break; case osmium::item_type::way: if (e.way_ids.get(member.positive_ref())) { e.relation_ids.set(relation.positive_id()); if (strategy().check_type(relation)) { e.add_relation(relation); } return; } break; default: break; } } } osmium::index::RelationsMapStash& relations_map_stash() noexcept { return m_relations_map_stash; } }; // class Pass1 class Pass2 : public Pass { public: Pass2(Strategy& strategy) : Pass(strategy) { } void eway(extract_data& e, const osmium::Way& way) { if (e.way_ids.get(way.positive_id()) || e.extra_way_ids.get(way.positive_id())) { for (const auto& nr : way.nodes()) { e.extra_node_ids.set(nr.ref()); } } } }; // class Pass2 class Pass3 : public Pass { public: Pass3(Strategy& strategy) : Pass(strategy) { } void enode(extract_data& e, const osmium::Node& node) { if (e.node_ids.get(node.positive_id()) || e.extra_node_ids.get(node.positive_id())) { e.write(node); } } void eway(extract_data& e, const osmium::Way& way) { if (e.way_ids.get(way.positive_id()) || e.extra_way_ids.get(way.positive_id())) { e.write(way); } } void erelation(extract_data& e, const osmium::Relation& relation) { if (e.relation_ids.get(relation.positive_id()) || e.extra_relation_ids.get(relation.positive_id())) { e.write(relation); } } }; // class Pass3 void Strategy::run(osmium::util::VerboseOutput& vout, bool display_progress, const osmium::io::File& input_file) { vout << "Running 'smart' strategy in three passes...\n"; const std::size_t file_size = osmium::util::file_size(input_file.filename()); osmium::ProgressBar progress_bar{file_size * 3, display_progress}; vout << "First pass...\n"; Pass1 pass1{*this}; pass1.run(progress_bar, input_file, osmium::io::read_meta::no); progress_bar.file_done(file_size); // recursively get parents of all relations that are in an extract const auto relations_map = pass1.relations_map_stash().build_member_to_parent_index(); for (auto& e : m_extracts) { for (osmium::unsigned_object_id_type id : e.relation_ids) { e.add_relation_parents(id, relations_map); } } progress_bar.remove(); vout << "Second pass...\n"; Pass2 pass2{*this}; pass2.run(progress_bar, input_file, osmium::osm_entity_bits::way, osmium::io::read_meta::no); progress_bar.file_done(file_size); progress_bar.remove(); vout << "Third pass...\n"; Pass3 pass3{*this}; pass3.run(progress_bar, input_file); progress_bar.done(); } } // namespace strategy_smart osmium-tool-1.7.1/src/extract/strategy_smart.hpp000066400000000000000000000050041315004223400220170ustar00rootroot00000000000000#ifndef EXTRACT_STRATEGY_SMART_HPP #define EXTRACT_STRATEGY_SMART_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include "strategy.hpp" namespace strategy_smart { struct Data { osmium::index::IdSetDense node_ids; osmium::index::IdSetDense extra_node_ids; osmium::index::IdSetDense way_ids; osmium::index::IdSetDense extra_way_ids; osmium::index::IdSetDense relation_ids; osmium::index::IdSetDense extra_relation_ids; void add_relation(const osmium::Relation& relation); void add_relation_parents(osmium::unsigned_object_id_type id, const osmium::index::RelationsMapIndex& map); }; class Strategy : public ExtractStrategy { template friend class ::Pass; friend class Pass1; using extract_data = ExtractData; std::vector m_extracts; std::vector m_types; bool check_type(const osmium::Relation& relation) const noexcept; public: explicit Strategy(const std::vector>& extracts, const osmium::util::Options& options); const char* name() const noexcept override final; void show_arguments(osmium::util::VerboseOutput& vout) override final; void run(osmium::util::VerboseOutput& vout, bool display_progress, const osmium::io::File& input_file) override final; }; // class Strategy } // namespace strategy_smart #endif // EXTRACT_STRATEGY_SMART_HPP osmium-tool-1.7.1/src/io.cpp000066400000000000000000000160361315004223400157060ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include // IWYU pragma: keep #include // IWYU pragma: keep #include #include #include #include #include "cmd.hpp" #include "exception.hpp" #include "util.hpp" void with_single_osm_input::setup_input_file(const boost::program_options::variables_map& vm) { if (vm.count("input-filename")) { m_input_filename = vm["input-filename"].as(); } if (vm.count("input-format")) { m_input_format = vm["input-format"].as(); } if (m_input_format.empty()) { if (m_input_filename == "-") { throw argument_error{"When reading from STDIN you need to use the --input-format/-F option\n" "to specify the file format."}; } if (m_input_filename == "") { throw argument_error{"Missing input file. Use '-' to read from STDIN and add the --input-format/-F\n" "option to specify the file format or specify the input file name."}; } } m_input_file = osmium::io::File{m_input_filename, m_input_format}; } po::options_description with_single_osm_input::add_single_input_options() { po::options_description options{"INPUT OPTIONS"}; options.add_options() ("input-format,F", po::value(), "Format of input file") ; return options; } void with_single_osm_input::show_single_input_arguments(osmium::util::VerboseOutput& vout) { vout << " input options:\n"; vout << " file name: " << m_input_filename << "\n"; vout << " file format: " << m_input_format << "\n"; } void with_multiple_osm_inputs::setup_input_files(const boost::program_options::variables_map& vm) { if (vm.count("input-filenames")) { m_input_filenames = vm["input-filenames"].as>(); } else { m_input_filenames.push_back("-"); // default is stdin } bool uses_stdin = false; for (auto& filename : m_input_filenames) { if (filename == "-") { if (uses_stdin) { throw argument_error{"Can read at most one file from STDIN."}; } uses_stdin = true; } } if (vm.count("input-format")) { m_input_format = vm["input-format"].as(); } if (uses_stdin && m_input_format.empty()) { throw argument_error{"When reading from STDIN you need to use the --input-format/-F option\n" "to specify the file format. Or are you missing a file name argument?"}; } for (const std::string& input_filename : m_input_filenames) { osmium::io::File input_file{input_filename, m_input_format}; m_input_files.push_back(input_file); } } po::options_description with_multiple_osm_inputs::add_multiple_inputs_options() { po::options_description options{"INPUT OPTIONS"}; options.add_options() ("input-format,F", po::value(), "Format of input files") ; return options; } void with_multiple_osm_inputs::show_multiple_inputs_arguments(osmium::util::VerboseOutput& vout) { vout << " input options:\n"; vout << " file names: \n"; for (const auto& fn : m_input_filenames) { vout << " " << fn << "\n"; } vout << " file format: " << m_input_format << "\n"; } void with_osm_output::init_output_file(const po::variables_map& vm) { if (vm.count("generator")) { m_generator = vm["generator"].as(); } if (vm.count("output")) { m_output_filename = vm["output"].as(); } if (vm.count("output-format")) { m_output_format = vm["output-format"].as(); } if (vm.count("output-header")) { m_output_headers = vm["output-header"].as>(); } if (vm.count("overwrite")) { m_output_overwrite = osmium::io::overwrite::allow; } if (vm.count("fsync")) { m_fsync = osmium::io::fsync::yes; } } void with_osm_output::check_output_file() { if (m_output_format.empty()) { if (m_output_filename == "-") { throw argument_error{"When writing to STDOUT you need to use the --output-format/-f\n" "option to specify the file format."}; } if (m_output_filename == "") { throw argument_error{"Missing output file. Set the output file with --output/-o and/or\n" "add the --output-format/-f option to specify the file format."}; } } m_output_file = osmium::io::File{m_output_filename, m_output_format}; m_output_file.check(); } void with_osm_output::setup_output_file(const po::variables_map& vm) { init_output_file(vm); check_output_file(); } po::options_description with_osm_output::add_output_options() { po::options_description options("OUTPUT OPTIONS"); options.add_options() ("output-format,f", po::value(), "Format of output file") ("fsync", "Call fsync after writing file") ("generator", po::value(), "Generator setting for file header") ("output,o", po::value(), "Output file") ("overwrite,O", "Allow existing output file to be overwritten") ("output-header", po::value>(), "Add output header") ; return options; } void with_osm_output::show_output_arguments(osmium::util::VerboseOutput& vout) { vout << " output options:\n"; vout << " file name: " << m_output_filename << "\n"; vout << " file format: " << m_output_format << "\n"; vout << " generator: " << m_generator << "\n"; vout << " overwrite: " << yes_no(m_output_overwrite == osmium::io::overwrite::allow); vout << " fsync: " << yes_no(m_fsync == osmium::io::fsync::yes); if (!m_output_headers.empty()) { vout << " output header:\n"; for (const auto& h : m_output_headers) { vout << " " << h << "\n"; } } } void with_osm_output::setup_header(osmium::io::Header& header) const { header.set("generator", m_generator); for (const auto& h : m_output_headers) { header.set(h); } } osmium-tool-1.7.1/src/main.cpp000066400000000000000000000110141315004223400162120ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #ifdef _WIN32 # include # include #endif #include #include #include #include "cmd.hpp" enum return_code : int { okay = 0, error = 1, fatal = 2 }; int main(int argc, char *argv[]) { #ifdef _WIN32 _setmode(1, _O_BINARY); #endif register_commands(); std::string command = argv[0]; // remove path from command // (backslash for windows, slash for everybody else) if (command.find_last_of("/\\") != std::string::npos) { command = command.substr(command.find_last_of("/\\") + 1); } std::vector arguments; for (int i = 1; i < argc; ++i) { arguments.push_back(argv[i]); } if (command == "osmium" || command == "osmium.exe") { if (arguments.size() == 0) { command = "help"; } else { if (arguments.front() == "--help" || arguments.front() == "-h") { command = "help"; } else if (arguments.front() == "--version") { command = "version"; } else { command = arguments.front(); } arguments.erase(arguments.begin()); } } else { if (command.substr(0, 7) == "osmium-") { command = command.substr(7); } } if (command == "version") { std::cout << get_osmium_long_version() << '\n' << get_libosmium_version() << '\n' << "Copyright (C) 2013-2017 Jochen Topf \n" << "License: GNU GENERAL PUBLIC LICENSE Version 3 .\n" << "This is free software: you are free to change and redistribute it.\n" << "There is NO WARRANTY, to the extent permitted by law.\n"; return return_code::okay; } std::unique_ptr cmd = CommandFactory::instance().create_command(command); if (!cmd) { std::cerr << "Unknown command or option '" << command << "'. Try 'osmium help'.\n"; return return_code::fatal; } try { if (!cmd->setup(arguments)) { return return_code::okay; } } catch (const boost::program_options::error& e) { std::cerr << "Error parsing command line: " << e.what() << '\n'; return return_code::fatal; } catch (const std::exception& e) { std::cerr << e.what() << '\n'; return return_code::fatal; } cmd->print_arguments(command); try { if (cmd->run()) { return return_code::okay; } } catch (const std::bad_alloc&) { std::cerr << "Out of memory. Read the MEMORY USAGE section of the osmium(1) manpage.\n"; } catch (const osmium::out_of_order_error& e) { std::cerr << e.what() << '\n'; std::cerr << "This command expects the input file to be ordered: First nodes in order of ID,\n" << "then ways in order of ID, then relations in order of ID.\n"; } catch (const std::system_error& e) { std::cerr << e.what(); if (e.code().value() == EEXIST) { std::cerr << ". Try using --overwrite if you are sure you want to overwrite the file."; } std::cerr << '\n'; } catch (const osmium::geometry_error& e) { std::cerr << "Geometry error: " << e.what() << '\n'; } catch (const osmium::invalid_location& e) { std::cerr << "Geometry error: Invalid location. Usually this means a node was missing from the input data.\n"; } catch (const std::exception& e) { std::cerr << e.what() << '\n'; } return return_code::error; } osmium-tool-1.7.1/src/util.cpp000066400000000000000000000136061315004223400162540ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include "exception.hpp" #include "util.hpp" /** * Get the suffix of the given file name. The suffix is everything after * the *first* dot (.). So multiple suffixes will all be returned. * * france.poly -> poly * planet.osm.bz2 -> osm.bz2 * some/path/planet.osm.bz2 -> osm.bz2 */ std::string get_filename_suffix(const std::string& file_name) { auto slash = file_name.find_last_of('/'); if (slash == std::string::npos) { slash = 0; } const auto dot = file_name.find_first_of('.', slash); if (dot == std::string::npos) { return ""; } return file_name.substr(dot + 1); } const char* yes_no(bool choice) noexcept { return choice ? "yes\n" : "no\n"; } void warning(const char* text) { std::cerr << "WARNING: " << text; } void warning(const std::string& text) { std::cerr << "WARNING: " << text; } std::size_t file_size_sum(const std::vector& files) { std::size_t sum = 0; for (const auto& file : files) { sum += osmium::util::file_size(file.filename()); } return sum; } osmium::osm_entity_bits::type get_types(const std::string& str) { osmium::osm_entity_bits::type entities{osmium::osm_entity_bits::nothing}; for (const auto c : str) { switch (c) { case 'n': entities |= osmium::osm_entity_bits::node; break; case 'w': entities |= osmium::osm_entity_bits::way; break; case 'r': entities |= osmium::osm_entity_bits::relation; break; default: throw argument_error{std::string{"Unknown object type '"} + c + "' (allowed are 'n', 'w', and 'r')."}; } } return entities; } std::pair get_filter_expression(const std::string& str) { auto pos = str.find('/'); osmium::osm_entity_bits::type entities{osmium::osm_entity_bits::nwr}; if (pos == std::string::npos) { pos = 0; } else if (pos == 0) { pos = 1; } else { entities = get_types(str.substr(0, pos)); ++pos; } return std::make_pair(entities, &str[pos]); } void strip_whitespace(std::string& string) { while (!string.empty() && string.back() == ' ') { string.pop_back(); } const auto pos = string.find_first_not_of(' '); if (pos != std::string::npos) { string.erase(0, pos); } } osmium::StringMatcher get_string_matcher(std::string string) { strip_whitespace(string); if (string.size() == 1 && string.front() == '*') { return osmium::StringMatcher::always_true{}; } if (string.empty() || (string.back() != '*' && string.front() != '*')) { if (string.find(',') == std::string::npos) { return osmium::StringMatcher::equal{string}; } auto sstrings = osmium::split_string(string, ','); for (auto& s : sstrings) { strip_whitespace(s); } return osmium::StringMatcher::list{sstrings}; } auto s = string; if (s.back() == '*' && s.front() != '*') { s.pop_back(); return osmium::StringMatcher::prefix{s}; } if (s.front() == '*') { s.erase(0, 1); } if (!s.empty() && s.back() == '*') { s.pop_back(); } return osmium::StringMatcher::substring{s}; } osmium::TagMatcher get_tag_matcher(const std::string& expression) { const auto op_pos = expression.find('='); if (op_pos == std::string::npos) { return osmium::TagMatcher{get_string_matcher(expression)}; } auto key = expression.substr(0, op_pos); const auto value = expression.substr(op_pos + 1); bool invert = false; if (!key.empty() && key.back() == '!') { key.pop_back(); invert = true; } return osmium::TagMatcher{get_string_matcher(key), get_string_matcher(value), invert}; } void initialize_tags_filter(osmium::TagsFilter& tags_filter, bool default_result, const std::vector& strings) { tags_filter.set_default_result(default_result); for (const auto& str : strings) { assert(!str.empty()); tags_filter.add_rule(!default_result, get_tag_matcher(str)); } } osmium::Box parse_bbox(const std::string& str, const std::string& option_name) { const auto coordinates = osmium::split_string(str, ','); if (coordinates.size() != 4) { throw argument_error{std::string{"Need exactly four coordinates in "} + option_name + " option."}; } const osmium::Location bottom_left{std::atof(coordinates[0].c_str()), std::atof(coordinates[1].c_str())}; const osmium::Location top_right{std::atof(coordinates[2].c_str()), std::atof(coordinates[3].c_str())}; if (bottom_left.x() < top_right.x() && bottom_left.y() < top_right.y()) { return osmium::Box{bottom_left, top_right}; } throw argument_error{std::string{"Need LEFT < RIGHT and BOTTOM < TOP in "} + option_name + " option."}; } osmium-tool-1.7.1/src/util.hpp000066400000000000000000000035621315004223400162610ustar00rootroot00000000000000#ifndef UTIL_HPP #define UTIL_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2017 Jochen Topf This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include namespace osmium { class TagsFilter; namespace io { class File; } } std::string get_filename_suffix(const std::string& file_name); const char* yes_no(bool choice) noexcept; void warning(const char* text); void warning(const std::string& text); std::size_t file_size_sum(const std::vector& files); osmium::osm_entity_bits::type get_types(const std::string& s); std::pair get_filter_expression(const std::string& s); void strip_whitespace(std::string& string); osmium::StringMatcher get_string_matcher(std::string string); osmium::TagMatcher get_tag_matcher(const std::string& expression); void initialize_tags_filter(osmium::TagsFilter& tags_filter, bool default_result, const std::vector& strings); osmium::Box parse_bbox(const std::string& str, const std::string& option_name); #endif // UTIL_HPP osmium-tool-1.7.1/src/version.cpp.in000066400000000000000000000005161315004223400173650ustar00rootroot00000000000000 #include const char* get_osmium_version() noexcept { return "@OSMIUM_VERSION@"; } const char* get_osmium_long_version() noexcept { return "osmium version @OSMIUM_VERSION@@VERSION_FROM_GIT@"; } const char* get_libosmium_version() noexcept { return "libosmium version " LIBOSMIUM_VERSION_STRING; } osmium-tool-1.7.1/test/000077500000000000000000000000001315004223400147555ustar00rootroot00000000000000osmium-tool-1.7.1/test/CMakeLists.txt000066400000000000000000000075631315004223400175300ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests # #----------------------------------------------------------------------------- include_directories(include) include_directories(../src) include_directories(../src/extract) include_directories(../include) file(GLOB ALL_UNIT_TESTS */test_setup.cpp */test_unit.cpp) file(GLOB ALL_COMMANDS ../src/command_*.cpp ../src/io.cpp ../src/cmd.cpp ../src/cmd_factory.cpp ../src/util.cpp ../src/*/*.cpp) add_executable(unit_tests unit_tests.cpp ${ALL_COMMANDS} ${ALL_UNIT_TESTS} ${PROJECT_BINARY_DIR}/src/version.cpp) target_link_libraries(unit_tests ${Boost_LIBRARIES} ${OSMIUM_LIBRARIES}) set_pthread_on_target(unit_tests) add_test(NAME unit_tests COMMAND unit_tests WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}") #----------------------------------------------------------------------------- configure_file(io/Makefile.in ${CMAKE_CURRENT_BINARY_DIR}/io/Makefile @ONLY) #----------------------------------------------------------------------------- function(do_test _name _command _regex) separate_arguments(_command) add_test(NAME ${_name} COMMAND ${_command}) set_tests_properties(${_name} PROPERTIES ENVIRONMENT "MANPATH=${PROJECT_BINARY_DIR}/man" PASS_REGULAR_EXPRESSION ${_regex} ) endfunction() #----------------------------------------------------------------------------- function(check_output _dir _name _command _reference) set(_cmd "$ ${_command}") add_test( NAME "${_dir}-${_name}" COMMAND ${CMAKE_COMMAND} -D cmd:FILEPATH=${_cmd} -D dir:PATH=${PROJECT_SOURCE_DIR}/test -D reference:FILEPATH=${PROJECT_SOURCE_DIR}/test/${_reference} -D output:FILEPATH=${PROJECT_BINARY_DIR}/test/${_dir}/cmd-output-${_name} -P ${CMAKE_SOURCE_DIR}/cmake/run_test_compare_output.cmake ) endfunction() function(check_output2 _dir _name _tmpdir _command1 _command2 _reference) set(_cmd1 "$ ${_command1}") set(_cmd2 "$ ${_command2}") add_test( NAME "${_dir}-${_name}" COMMAND ${CMAKE_COMMAND} -D cmd:FILEPATH=${_cmd1} -D cmd2:FILEPATH=${_cmd2} -D dir:PATH=${PROJECT_SOURCE_DIR}/test -D tmpdir:PATH=${_tmpdir} -D reference:FILEPATH=${PROJECT_SOURCE_DIR}/test/${_reference} -D output:FILEPATH=${PROJECT_BINARY_DIR}/test/${_dir}/cmd-output-${_name} -P ${CMAKE_SOURCE_DIR}/cmake/run_test_compare_output.cmake ) endfunction() #----------------------------------------------------------------------------- # # Check "osmium SUBCOMMAND -h" for most subcommands. # #----------------------------------------------------------------------------- function(check_cmd_help _command) do_test(help_cmd_${_command} "osmium ${_command} -h" "Usage: osmium ${_command}.*OPTIONS:") endfunction() check_cmd_help(add-locations-to-ways) check_cmd_help(apply-changes) check_cmd_help(cat) check_cmd_help(changeset-filter) check_cmd_help(check-refs) check_cmd_help(derive-changes) check_cmd_help(diff) check_cmd_help(export) check_cmd_help(extract) check_cmd_help(fileinfo) check_cmd_help(getid) check_cmd_help(merge) check_cmd_help(merge-changes) check_cmd_help(renumber) check_cmd_help(show) check_cmd_help(sort) check_cmd_help(tags-filter) check_cmd_help(time-filter) #----------------------------------------------------------------------------- # # Configure tests in all subdirectories # #----------------------------------------------------------------------------- file(GLOB _testcmakes "test" "*/CMakeLists.txt") foreach(_tc IN LISTS _testcmakes) string(REPLACE "/CMakeLists.txt" "" _dir ${_tc}) message(STATUS "Adding tests in ${_dir}") add_subdirectory(${_dir}) endforeach() #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/add-locations-to-ways/000077500000000000000000000000001315004223400210775ustar00rootroot00000000000000osmium-tool-1.7.1/test/add-locations-to-ways/CMakeLists.txt000066400000000000000000000013061315004223400236370ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - add-locations-to-ways # #----------------------------------------------------------------------------- function(check_add_locations_to_ways _name _options _input _output) check_output(add-locations-to-ways ${_name} "add-locations-to-ways ${_options} --generator=test --output-format=xml add-locations-to-ways/${_input}" "add-locations-to-ways/${_output}") endfunction() check_add_locations_to_ways(taggednodes "" input.osm output.osm) check_add_locations_to_ways(allnodes "-n" input.osm output-n.osm) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/add-locations-to-ways/input.osm000066400000000000000000000016641315004223400227650ustar00rootroot00000000000000 osmium-tool-1.7.1/test/add-locations-to-ways/output-n.osm000066400000000000000000000017611315004223400234170ustar00rootroot00000000000000 osmium-tool-1.7.1/test/add-locations-to-ways/output.osm000066400000000000000000000012361315004223400231610ustar00rootroot00000000000000 osmium-tool-1.7.1/test/apply-changes/000077500000000000000000000000001315004223400175105ustar00rootroot00000000000000osmium-tool-1.7.1/test/apply-changes/CMakeLists.txt000066400000000000000000000034061315004223400222530ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - apply-changes # #----------------------------------------------------------------------------- function(check_apply_changes _name _options _input _change _type _output) check_output(apply-changes ${_name} "apply-changes ${_options} --generator=test -f ${_type} apply-changes/${_input} apply-changes/${_change}" "apply-changes/${_output}") endfunction() check_apply_changes(data "" input-data.osm input-change.osc "osm" output-data.osm) add_test(NAME check-apply-changes-mixed1 COMMAND osmium apply-changes ${CMAKE_SOURCE_DIR}/test/apply-changes/input-data.osm ${CMAKE_SOURCE_DIR}/test/apply-changes/input-changes.osc -f osh) set_tests_properties(check-apply-changes-mixed1 PROPERTIES WILL_FAIL true) add_test(NAME check-apply-changes-mixed2 COMMAND osmium apply-changes ${CMAKE_SOURCE_DIR}/test/apply-changes/input-data.osh ${CMAKE_SOURCE_DIR}/test/apply-changes/input-changes.osc -f osm) set_tests_properties(check-apply-changes-mixed2 PROPERTIES WILL_FAIL true) check_apply_changes(history-osh-osh "" input-history.osh input-change.osc "osh" output-history.osh) check_apply_changes(history-osh-osh-wh "--with-history" input-history.osh input-change.osc "osh" output-history.osh) check_apply_changes(history-osm-osh-wh "--with-history" input-history.osm input-change.osc "osh" output-history.osh) check_apply_changes(history-osh-osm-wh "--with-history" input-history.osh input-change.osc "osm" output-history.osh) check_apply_changes(data-low "--locations-on-ways" input-data-low.osm input-change.osc "osm" output-data-low.osm) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/apply-changes/input-change.osc000066400000000000000000000013131315004223400225760ustar00rootroot00000000000000 osmium-tool-1.7.1/test/apply-changes/input-data-low.osm000066400000000000000000000022521315004223400230760ustar00rootroot00000000000000 osmium-tool-1.7.1/test/apply-changes/input-data.osm000066400000000000000000000021321315004223400222740ustar00rootroot00000000000000 osmium-tool-1.7.1/test/apply-changes/input-history.osh000066400000000000000000000023131315004223400230600ustar00rootroot00000000000000 osmium-tool-1.7.1/test/apply-changes/input-history.osm000066400000000000000000000023131315004223400230650ustar00rootroot00000000000000 osmium-tool-1.7.1/test/apply-changes/output-data-low.osm000066400000000000000000000022271315004223400233010ustar00rootroot00000000000000 osmium-tool-1.7.1/test/apply-changes/output-data.osm000066400000000000000000000021071315004223400224770ustar00rootroot00000000000000 osmium-tool-1.7.1/test/apply-changes/output-history.osh000066400000000000000000000035511315004223400232660ustar00rootroot00000000000000 osmium-tool-1.7.1/test/cat/000077500000000000000000000000001315004223400155245ustar00rootroot00000000000000osmium-tool-1.7.1/test/cat/CMakeLists.txt000066400000000000000000000015751315004223400202740ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - cat # #----------------------------------------------------------------------------- function(check_cat _name _in1 _in2 _output) check_output(cat ${_name} "cat --no-progress --generator=test -f osm cat/${_in1} cat/${_in2}" "cat/${_output}") endfunction() function(check_convert _name _input _output _format) check_output(cat ${_name} "cat --no-progress --generator=test cat/${_input} -f ${_format}" "cat/${_output}") endfunction() #----------------------------------------------------------------------------- check_cat(cat12 input1.osm input2.osm output-cat12.osm) check_cat(cat21 input2.osm input1.osm output-cat21.osm) check_convert(osm2opl input1.osm output1.osm.opl opl) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/cat/input1.osm000066400000000000000000000006661315004223400174740ustar00rootroot00000000000000 osmium-tool-1.7.1/test/cat/input2.osm000066400000000000000000000006661315004223400174750ustar00rootroot00000000000000 osmium-tool-1.7.1/test/cat/output-cat12.osm000066400000000000000000000013631315004223400205170ustar00rootroot00000000000000 osmium-tool-1.7.1/test/cat/output-cat21.osm000066400000000000000000000013631315004223400205170ustar00rootroot00000000000000 osmium-tool-1.7.1/test/cat/output1.osm.opl000066400000000000000000000002311315004223400204520ustar00rootroot00000000000000n1 v1 dV c1 t2015-01-01T01:00:00Z i1 utest T x1 y1 n2 v1 dV c1 t2015-01-01T01:00:00Z i1 utest T x1 y2 n3 v1 dV c1 t2015-01-01T01:00:00Z i1 utest T x1 y3 osmium-tool-1.7.1/test/cat/test_setup.cpp000066400000000000000000000052751315004223400204400ustar00rootroot00000000000000 #include "test.hpp" // IWYU pragma: keep #include "command_cat.hpp" TEST_CASE("cat") { CommandCat cmd; SECTION("no parameters") { REQUIRE_THROWS_AS(cmd.setup({}), argument_error); } SECTION("stdin osm to stdout pbf") { cmd.setup({"-F", "osm", "-f", "pbf"}); auto ifs = cmd.input_files(); REQUIRE(ifs.size() == 1); REQUIRE(ifs.front().format() == osmium::io::file_format::xml); REQUIRE(ifs.front().compression() == osmium::io::file_compression::none); REQUIRE(ifs.front().filename() == ""); auto of = cmd.output_file(); REQUIRE(of.format() == osmium::io::file_format::pbf); REQUIRE(of.filename() == ""); REQUIRE(cmd.output_overwrite() == osmium::io::overwrite::no); REQUIRE(cmd.osm_entity_bits() == osmium::osm_entity_bits::all); } SECTION("unknown object-type 1") { REQUIRE_THROWS_AS(cmd.setup({"in.osm", "-o", "out.osm", "-t", "foo"}), argument_error); } SECTION("unknown object-type 2") { REQUIRE_THROWS_AS(cmd.setup({"in.osm", "-o", "out.osm", "--object-type", "foo"}), argument_error); } SECTION("reading to files") { cmd.setup({"-o", "output", "-O", "-f", "opl", "-t", "way", "a.osm.bz2", "b.pbf"}); auto ifs = cmd.input_files(); REQUIRE(ifs.size() == 2); REQUIRE(ifs[0].format() == osmium::io::file_format::xml); REQUIRE(ifs[0].compression() == osmium::io::file_compression::bzip2); REQUIRE(ifs[0].filename() == "a.osm.bz2"); REQUIRE(ifs[1].format() == osmium::io::file_format::pbf); REQUIRE(ifs[1].compression() == osmium::io::file_compression::none); REQUIRE(ifs[1].filename() == "b.pbf"); auto of = cmd.output_file(); REQUIRE(of.format() == osmium::io::file_format::opl); REQUIRE(of.filename() == "output"); REQUIRE(cmd.output_overwrite() == osmium::io::overwrite::allow); REQUIRE(cmd.osm_entity_bits() == osmium::osm_entity_bits::way); } SECTION("unknown input format suffix") { REQUIRE_THROWS_AS(cmd.setup({"in.foo"}), argument_error); } SECTION("unknown input format option") { REQUIRE_THROWS_AS(cmd.setup({"in.osm", "-F", "foo"}), argument_error); } SECTION("unknown output format suffix") { REQUIRE_THROWS_AS(cmd.setup({"in.osm", "-o", "foo.bar"}), std::runtime_error); } SECTION("unknown output suffix and unknown format option") { REQUIRE_THROWS_AS(cmd.setup({"in.osm", "-o", "foo.foo", "-f", "bar"}), std::runtime_error); } SECTION("unknown output format option") { REQUIRE_THROWS_AS(cmd.setup({"in.osm", "-o", "foo.pbf", "-f", "bar"}), std::runtime_error); } } osmium-tool-1.7.1/test/changeset-filter/000077500000000000000000000000001315004223400202015ustar00rootroot00000000000000osmium-tool-1.7.1/test/changeset-filter/CMakeLists.txt000066400000000000000000000120321315004223400227370ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - changeset-filter # #----------------------------------------------------------------------------- function(check_changeset_filter _name _options _input _output) check_output(changeset-filter ${_name} "changeset-filter --generator=test -f osm ${_options} changeset-filter/${_input}" "changeset-filter/${_output}") endfunction() #----------------------------------------------------------------------------- check_changeset_filter(cf1-no-option "" input1.osm output1-all.osm) check_changeset_filter(cf1-with-discussion "--with-discussion" input1.osm output-empty.osm) check_changeset_filter(cf1-without-discussion "--without-discussion" input1.osm output1-all.osm) check_changeset_filter(cf1-with-changes "--with-changes" input1.osm output1-first.osm) check_changeset_filter(cf1-without-changes "--without-changes" input1.osm output1-second.osm) check_changeset_filter(cf1-open "--open" input1.osm output-empty.osm) check_changeset_filter(cf1-closed "--closed" input1.osm output1-all.osm) check_changeset_filter(cf1-user "--user=Elbert" input1.osm output1-first.osm) check_changeset_filter(cf1-uid "--uid=1233268" input1.osm output1-second.osm) check_changeset_filter(cfe-open "--open" input-open.osm output-open.osm) check_changeset_filter(cfe-closed "--closed" input-open.osm output-empty.osm) check_changeset_filter(cf1-after01 "--after=2013-03-22T02:08:50Z" input1.osm output1-all.osm) check_changeset_filter(cf1-after02 "--after=2013-03-22T02:08:54Z" input1.osm output1-all.osm) check_changeset_filter(cf1-after03 "--after=2013-03-22T02:08:55Z" input1.osm output1-all.osm) check_changeset_filter(cf1-after04 "--after=2013-03-22T02:08:56Z" input1.osm output1-all.osm) check_changeset_filter(cf1-after05 "--after=2013-03-22T02:08:57Z" input1.osm output1-all.osm) check_changeset_filter(cf1-after06 "--after=2013-03-22T02:08:58Z" input1.osm output1-all.osm) check_changeset_filter(cf1-after07 "--after=2013-03-22T02:08:59Z" input1.osm output1-second.osm) check_changeset_filter(cf1-after08 "--after=2013-03-22T02:09:00Z" input1.osm output1-second.osm) check_changeset_filter(cf1-after09 "--after=2013-03-22T02:09:10Z" input1.osm output1-second.osm) check_changeset_filter(cf1-after10 "--after=2013-03-22T02:09:11Z" input1.osm output1-second.osm) check_changeset_filter(cf1-after11 "--after=2013-03-22T02:09:12Z" input1.osm output1-second.osm) check_changeset_filter(cf1-after12 "--after=2013-03-22T03:09:10Z" input1.osm output1-second.osm) check_changeset_filter(cf1-after13 "--after=2013-03-22T03:09:11Z" input1.osm output1-second.osm) check_changeset_filter(cf1-after14 "--after=2013-03-22T03:09:12Z" input1.osm output-empty.osm) check_changeset_filter(cf1-after15 "--after=2013-03-22T03:09:20Z" input1.osm output-empty.osm) check_changeset_filter(cfe-after01 "--after=2013-03-22T04:20:24Z" input-open.osm output-open.osm) check_changeset_filter(cfe-after02 "--after=2013-03-22T04:20:25Z" input-open.osm output-open.osm) check_changeset_filter(cfe-after03 "--after=2013-03-22T04:20:26Z" input-open.osm output-open.osm) check_changeset_filter(cf1-before01 "--before=2013-03-22T02:08:50Z" input1.osm output-empty.osm) check_changeset_filter(cf1-before02 "--before=2013-03-22T02:08:54Z" input1.osm output-empty.osm) check_changeset_filter(cf1-before03 "--before=2013-03-22T02:08:55Z" input1.osm output1-first.osm) check_changeset_filter(cf1-before04 "--before=2013-03-22T02:08:56Z" input1.osm output1-first.osm) check_changeset_filter(cf1-before05 "--before=2013-03-22T02:08:57Z" input1.osm output1-first.osm) check_changeset_filter(cf1-before06 "--before=2013-03-22T02:08:58Z" input1.osm output1-first.osm) check_changeset_filter(cf1-before07 "--before=2013-03-22T02:08:59Z" input1.osm output1-first.osm) check_changeset_filter(cf1-before08 "--before=2013-03-22T02:09:00Z" input1.osm output1-first.osm) check_changeset_filter(cf1-before09 "--before=2013-03-22T02:09:10Z" input1.osm output1-first.osm) check_changeset_filter(cf1-before10 "--before=2013-03-22T02:09:11Z" input1.osm output1-all.osm) check_changeset_filter(cf1-before11 "--before=2013-03-22T02:09:12Z" input1.osm output1-all.osm) check_changeset_filter(cf1-before12 "--before=2013-03-22T03:09:10Z" input1.osm output1-all.osm) check_changeset_filter(cf1-before13 "--before=2013-03-22T03:09:11Z" input1.osm output1-all.osm) check_changeset_filter(cf1-before14 "--before=2013-03-22T03:09:12Z" input1.osm output1-all.osm) check_changeset_filter(cf1-before15 "--before=2013-03-22T03:09:20Z" input1.osm output1-all.osm) check_changeset_filter(cfe-before01 "--before=2013-03-22T04:20:24Z" input-open.osm output-empty.osm) check_changeset_filter(cfe-before02 "--before=2013-03-22T04:20:25Z" input-open.osm output-open.osm) check_changeset_filter(cfe-before03 "--before=2013-03-22T04:20:26Z" input-open.osm output-open.osm) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/changeset-filter/input-open.osm000066400000000000000000000005271315004223400230230ustar00rootroot00000000000000 osmium-tool-1.7.1/test/changeset-filter/input1.osm000066400000000000000000000012131315004223400221360ustar00rootroot00000000000000 osmium-tool-1.7.1/test/changeset-filter/output-empty.osm000066400000000000000000000001231315004223400234110ustar00rootroot00000000000000 osmium-tool-1.7.1/test/changeset-filter/output-open.osm000066400000000000000000000005421315004223400232210ustar00rootroot00000000000000 osmium-tool-1.7.1/test/changeset-filter/output1-all.osm000066400000000000000000000012471315004223400231140ustar00rootroot00000000000000 osmium-tool-1.7.1/test/changeset-filter/output1-first.osm000066400000000000000000000006211315004223400234660ustar00rootroot00000000000000 osmium-tool-1.7.1/test/changeset-filter/output1-second.osm000066400000000000000000000005511315004223400236140ustar00rootroot00000000000000 osmium-tool-1.7.1/test/check-refs/000077500000000000000000000000001315004223400167675ustar00rootroot00000000000000osmium-tool-1.7.1/test/check-refs/CMakeLists.txt000066400000000000000000000055501315004223400215340ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - check-refs # #----------------------------------------------------------------------------- add_test(NAME check-ref-w-okay COMMAND osmium check-refs ${CMAKE_SOURCE_DIR}/test/check-refs/okay.osm) add_test(NAME check-ref-r-okay COMMAND osmium check-refs -r ${CMAKE_SOURCE_DIR}/test/check-refs/okay.osm) add_test(NAME check-ref-fail-n-in-w COMMAND osmium check-refs ${CMAKE_SOURCE_DIR}/test/check-refs/fail-n-in-w.osm) set_tests_properties(check-ref-fail-n-in-w PROPERTIES WILL_FAIL true) add_test(NAME check-ref-w-way-okay COMMAND osmium check-refs ${CMAKE_SOURCE_DIR}/test/check-refs/way-okay.osm) add_test(NAME check-ref-r-way-okay COMMAND osmium check-refs -r ${CMAKE_SOURCE_DIR}/test/check-refs/way-okay.osm) set_tests_properties(check-ref-r-way-okay PROPERTIES WILL_FAIL true) add_test(NAME check-ref-okay-r-in-r COMMAND osmium check-refs -r ${CMAKE_SOURCE_DIR}/test/check-refs/okay-r-in-r.osm) add_test(NAME check-ref-fail-n-in-r COMMAND osmium check-refs -r ${CMAKE_SOURCE_DIR}/test/check-refs/fail-n-in-r.osm) set_tests_properties(check-ref-fail-n-in-r PROPERTIES WILL_FAIL true) add_test(NAME check-ref-fail-w-in-r COMMAND osmium check-refs -r ${CMAKE_SOURCE_DIR}/test/check-refs/fail-w-in-r.osm) set_tests_properties(check-ref-fail-w-in-r PROPERTIES WILL_FAIL true) add_test(NAME check-ref-fail-r-in-r-1 COMMAND osmium check-refs -r ${CMAKE_SOURCE_DIR}/test/check-refs/fail-r-in-r-1.osm) set_tests_properties(check-ref-fail-r-in-r-1 PROPERTIES WILL_FAIL true) add_test(NAME check-ref-fail-r-in-r-2 COMMAND osmium check-refs -r ${CMAKE_SOURCE_DIR}/test/check-refs/fail-r-in-r-2.osm) set_tests_properties(check-ref-fail-r-in-r-2 PROPERTIES WILL_FAIL true) #----------------------------------------------------------------------------- # input data not ordered properly add_test(NAME check-ref-fail-order-n COMMAND osmium check-refs ${CMAKE_SOURCE_DIR}/test/order/fail-order-n.osm) set_tests_properties(check-ref-fail-order-n PROPERTIES WILL_FAIL true) add_test(NAME check-ref-fail-order-w COMMAND osmium check-refs ${CMAKE_SOURCE_DIR}/test/order/fail-order-w.osm) set_tests_properties(check-ref-fail-order-w PROPERTIES WILL_FAIL true) add_test(NAME check-ref-fail-order-r COMMAND osmium check-refs -r ${CMAKE_SOURCE_DIR}/test/order/fail-order-r.osm) set_tests_properties(check-ref-fail-order-r PROPERTIES WILL_FAIL true) add_test(NAME check-ref-fail-order-wn COMMAND osmium check-refs ${CMAKE_SOURCE_DIR}/test/order/fail-order-wn.osm) set_tests_properties(check-ref-fail-order-wn PROPERTIES WILL_FAIL true) add_test(NAME check-ref-fail-order-rw COMMAND osmium check-refs ${CMAKE_SOURCE_DIR}/test/order/fail-order-rw.osm) set_tests_properties(check-ref-fail-order-rw PROPERTIES WILL_FAIL true) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/check-refs/fail-n-in-r.osm000066400000000000000000000004031315004223400215150ustar00rootroot00000000000000 osmium-tool-1.7.1/test/check-refs/fail-n-in-w.osm000066400000000000000000000007261315004223400215320ustar00rootroot00000000000000 osmium-tool-1.7.1/test/check-refs/fail-r-in-r-1.osm000066400000000000000000000004071315004223400216630ustar00rootroot00000000000000 osmium-tool-1.7.1/test/check-refs/fail-r-in-r-2.osm000066400000000000000000000004071315004223400216640ustar00rootroot00000000000000 osmium-tool-1.7.1/test/check-refs/fail-w-in-r.osm000066400000000000000000000004021315004223400215250ustar00rootroot00000000000000 osmium-tool-1.7.1/test/check-refs/okay-r-in-r.osm000066400000000000000000000006501315004223400215550ustar00rootroot00000000000000 osmium-tool-1.7.1/test/check-refs/okay.osm000066400000000000000000000017061315004223400204560ustar00rootroot00000000000000 osmium-tool-1.7.1/test/check-refs/way-okay.osm000066400000000000000000000014411315004223400212500ustar00rootroot00000000000000 osmium-tool-1.7.1/test/derive-changes/000077500000000000000000000000001315004223400176415ustar00rootroot00000000000000osmium-tool-1.7.1/test/derive-changes/CMakeLists.txt000066400000000000000000000015301315004223400224000ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - derive-changes # #----------------------------------------------------------------------------- function(check_derive_changes _name _options _input1 _input2 _output) check_output(derive-changes ${_name} "derive-changes --generator=test -f osc ${_options} derive-changes/${_input1} derive-changes/${_input2}" "derive-changes/${_output}") endfunction() check_derive_changes(normal "" input1.osm input2.osm output.osc) check_derive_changes(keep_details "--keep-details" input1.osm input2.osm output-keep-details.osc) check_derive_changes(incr_version "--increment-version" input1.osm input2.osm output-incr-version.osc) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/derive-changes/input1.osm000066400000000000000000000021761315004223400216070ustar00rootroot00000000000000 osmium-tool-1.7.1/test/derive-changes/input2.osm000066400000000000000000000021071315004223400216020ustar00rootroot00000000000000 osmium-tool-1.7.1/test/derive-changes/output-incr-version.osc000066400000000000000000000012251315004223400243230ustar00rootroot00000000000000 osmium-tool-1.7.1/test/derive-changes/output-keep-details.osc000066400000000000000000000013571315004223400242620ustar00rootroot00000000000000 osmium-tool-1.7.1/test/derive-changes/output.osc000066400000000000000000000012251315004223400217070ustar00rootroot00000000000000 osmium-tool-1.7.1/test/diff/000077500000000000000000000000001315004223400156655ustar00rootroot00000000000000osmium-tool-1.7.1/test/diff/CMakeLists.txt000066400000000000000000000017171315004223400204330ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - diff # #----------------------------------------------------------------------------- function(check_diff _name _options _input1 _input2 _output) check_output(diff ${_name} "diff ${_options} --generator=test diff/${_input1} diff/${_input2}" "diff/${_output}") endfunction() check_diff(compact "" input1.osm input2.osm output-compact) set_tests_properties(diff-compact PROPERTIES WILL_FAIL true) check_diff(compact-c "-c" input1.osm input2.osm output-compact-c) set_tests_properties(diff-compact-c PROPERTIES WILL_FAIL true) check_diff(opl "-f opl" input1.osm input2.osm output.opl) set_tests_properties(diff-opl PROPERTIES WILL_FAIL true) check_diff(opl-c "-f opl -c" input1.osm input2.osm output-c.opl) set_tests_properties(diff-opl-c PROPERTIES WILL_FAIL true) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/diff/input1.osm000066400000000000000000000024741315004223400176340ustar00rootroot00000000000000 osmium-tool-1.7.1/test/diff/input2.osm000066400000000000000000000024511315004223400176300ustar00rootroot00000000000000 osmium-tool-1.7.1/test/diff/output-c.opl000066400000000000000000000010461315004223400201620ustar00rootroot00000000000000-n11 v1 dV c1 t2015-01-01T01:00:00Z i1 utest T x1 y2 +n11 v2 dV c2 t2015-01-01T02:00:00Z i1 utest T x2 y2 -n13 v1 dV c1 t2015-01-01T01:00:00Z i1 utest T x1 y4 +n14 v1 dV c2 t2015-01-01T02:00:00Z i1 utest T x1 y5 -n15 v1 dV c1 t2015-01-01T02:00:00Z i2 utest T x1 y5 +n15 v1 dV c1 t2015-01-01T02:00:00Z i1 utest T x1 y5 -n16 v1 dV c1 t2015-01-01T02:00:00Z i1 utest T x2 y5 +n16 v1 dV c1 t2015-01-01T02:00:00Z i1 utest T x1 y5 -w21 v1 dV c1 t2015-01-01T01:00:00Z i1 utest Txyz=abc Nn12,n13 +w21 v2 dV c2 t2015-01-01T02:00:00Z i1 utest Txyz=new Nn12,n14 osmium-tool-1.7.1/test/diff/output-compact000066400000000000000000000001401315004223400205670ustar00rootroot00000000000000 n10 v1 -n11 v1 +n11 v2 n12 v1 -n13 v1 +n14 v1 *n15 v1 *n16 v1 w20 v1 -w21 v1 +w21 v2 r30 v1 osmium-tool-1.7.1/test/diff/output-compact-c000066400000000000000000000001001315004223400210030ustar00rootroot00000000000000-n11 v1 +n11 v2 -n13 v1 +n14 v1 *n15 v1 *n16 v1 -w21 v1 +w21 v2 osmium-tool-1.7.1/test/diff/output.opl000066400000000000000000000014211315004223400177370ustar00rootroot00000000000000 n10 v1 dV c1 t2015-01-01T01:00:00Z i1 utest T x1 y1 -n11 v1 dV c1 t2015-01-01T01:00:00Z i1 utest T x1 y2 +n11 v2 dV c2 t2015-01-01T02:00:00Z i1 utest T x2 y2 n12 v1 dV c1 t2015-01-01T01:00:00Z i1 utest T x1 y3 -n13 v1 dV c1 t2015-01-01T01:00:00Z i1 utest T x1 y4 +n14 v1 dV c2 t2015-01-01T02:00:00Z i1 utest T x1 y5 -n15 v1 dV c1 t2015-01-01T02:00:00Z i2 utest T x1 y5 +n15 v1 dV c1 t2015-01-01T02:00:00Z i1 utest T x1 y5 -n16 v1 dV c1 t2015-01-01T02:00:00Z i1 utest T x2 y5 +n16 v1 dV c1 t2015-01-01T02:00:00Z i1 utest T x1 y5 w20 v1 dV c1 t2015-01-01T01:00:00Z i1 utest Tfoo=bar Nn10,n11,n12 -w21 v1 dV c1 t2015-01-01T01:00:00Z i1 utest Txyz=abc Nn12,n13 +w21 v2 dV c2 t2015-01-01T02:00:00Z i1 utest Txyz=new Nn12,n14 r30 v1 dV c1 t2015-01-01T01:00:00Z i1 utest T Mn12@m1,w20@m2 osmium-tool-1.7.1/test/diff/test_setup.cpp000066400000000000000000000017551315004223400206000ustar00rootroot00000000000000 #include "test.hpp" #include "command_diff.hpp" TEST_CASE("diff") { CommandDiff cmd; SECTION("no arguments - need exactly two arguments") { REQUIRE_THROWS_AS(cmd.setup({}), argument_error); } SECTION("one argument - need exactly two arguments") { REQUIRE_THROWS_AS(cmd.setup({"x"}), argument_error); } SECTION("three arguments - need exactly two arguments") { REQUIRE_THROWS_AS(cmd.setup({"x", "y", "z"}), argument_error); } SECTION("quiet with output parameter -o") { REQUIRE_THROWS_AS(cmd.setup({"-q", "-o", "file"}), argument_error); } SECTION("quiet with output parameter -f") { REQUIRE_THROWS_AS(cmd.setup({"-q", "-f", "opl"}), argument_error); } SECTION("parameter --fsync") { REQUIRE_THROWS_AS(cmd.setup({"--fsync"}), boost::program_options::unknown_option); } SECTION("quiet with output parameter -O") { REQUIRE_THROWS_AS(cmd.setup({"-q", "-O"}), argument_error); } } osmium-tool-1.7.1/test/export/000077500000000000000000000000001315004223400162765ustar00rootroot00000000000000osmium-tool-1.7.1/test/export/CMakeLists.txt000066400000000000000000000020771315004223400210440ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - export # #----------------------------------------------------------------------------- function(check_export _name _options _input _output) check_output(export ${_name} "export ${_options} export/${_input}" "export/${_output}") endfunction() check_export(geojson "-f geojson" input.osm output.geojson) check_export(geojsonseq "-f geojsonseq -r" input.osm output.geojsonseq) check_export(missing-node "-f geojson" input-missing-node.osm output-missing-node.geojson) check_export(error-node "-f geojson -E" input-missing-node.osm none.geojson) set_tests_properties(export-error-node PROPERTIES WILL_FAIL true) check_export(invalid-area "-f geojson" input-incomplete-relation.osm output-incomplete-relation.geojson) check_export(error-area "-f geojson -E" input-incomplete-relation.osm none.geojson) set_tests_properties(export-error-area PROPERTIES WILL_FAIL true) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/export/input-incomplete-relation.osm000066400000000000000000000027041315004223400241300ustar00rootroot00000000000000 osmium-tool-1.7.1/test/export/input-missing-node.osm000066400000000000000000000026021315004223400225470ustar00rootroot00000000000000 osmium-tool-1.7.1/test/export/input.osm000066400000000000000000000027631315004223400201650ustar00rootroot00000000000000 osmium-tool-1.7.1/test/export/output-incomplete-relation.geojson000066400000000000000000000006371315004223400252020ustar00rootroot00000000000000{"type":"FeatureCollection","features":[ {"type":"Feature","geometry":{"type":"Point","coordinates":[2.0,1.5]},"properties":{"amenity":"post_box"}}, {"type":"Feature","geometry":{"type":"LineString","coordinates":[[1.0,1.0],[1.0,2.0],[1.0,3.0]]},"properties":{"highway":"track"}}, {"type":"Feature","geometry":{"type":"LineString","coordinates":[[1.0,1.0],[1.0,2.0],[2.0,1.5]]},"properties":{"barrier":"fence"}} ]} osmium-tool-1.7.1/test/export/output-missing-node.geojson000066400000000000000000000006601315004223400236200ustar00rootroot00000000000000{"type":"FeatureCollection","features":[ {"type":"Feature","geometry":{"type":"Point","coordinates":[2.0,1.5]},"properties":{"amenity":"post_box"}}, {"type":"Feature","geometry":{"type":"LineString","coordinates":[[1.0,1.0],[1.0,2.0],[2.0,1.5]]},"properties":{"barrier":"fence"}}, {"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[1.0,1.0],[2.0,1.5],[1.0,2.0],[1.0,1.0]]]]},"properties":{"landuse":"forest"}} ]} osmium-tool-1.7.1/test/export/output.geojson000066400000000000000000000010641315004223400212250ustar00rootroot00000000000000{"type":"FeatureCollection","features":[ {"type":"Feature","geometry":{"type":"Point","coordinates":[2.0,1.5]},"properties":{"amenity":"post_box"}}, {"type":"Feature","geometry":{"type":"LineString","coordinates":[[1.0,1.0],[1.0,2.0],[1.0,3.0]]},"properties":{"highway":"track"}}, {"type":"Feature","geometry":{"type":"LineString","coordinates":[[1.0,1.0],[1.0,2.0],[2.0,1.5]]},"properties":{"barrier":"fence"}}, {"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[1.0,1.0],[2.0,1.5],[1.0,2.0],[1.0,1.0]]]]},"properties":{"landuse":"forest"}} ]} osmium-tool-1.7.1/test/export/output.geojsonseq000066400000000000000000000010051315004223400217310ustar00rootroot00000000000000{"type":"Feature","geometry":{"type":"Point","coordinates":[2.0,1.5]},"properties":{"amenity":"post_box"}} {"type":"Feature","geometry":{"type":"LineString","coordinates":[[1.0,1.0],[1.0,2.0],[1.0,3.0]]},"properties":{"highway":"track"}} {"type":"Feature","geometry":{"type":"LineString","coordinates":[[1.0,1.0],[1.0,2.0],[2.0,1.5]]},"properties":{"barrier":"fence"}} {"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[1.0,1.0],[2.0,1.5],[1.0,2.0],[1.0,1.0]]]]},"properties":{"landuse":"forest"}} osmium-tool-1.7.1/test/extract/000077500000000000000000000000001315004223400164275ustar00rootroot00000000000000osmium-tool-1.7.1/test/extract/CMakeLists.txt000066400000000000000000000025031315004223400211670ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - extract # #----------------------------------------------------------------------------- function(check_extract _name _input _output _opts) check_output(extract ${_name} "extract --generator=test -f osm extract/${_input} ${_opts} -b 0,0,1.5,10" "extract/${_output}") endfunction() function(check_extract_cfg _name _input _output _opts) check_output(extract cfg_${_name} "extract --generator=test extract/${_input} ${_opts} -c ${CMAKE_CURRENT_SOURCE_DIR}/config.json" "extract/${_output}") endfunction() #----------------------------------------------------------------------------- check_extract(simple input1.osm output-simple.osm "-s simple") check_extract(complete_ways input1.osm output-complete-ways.osm "-s complete_ways") check_extract(smart_default input1.osm output-smart.osm "-s smart") check_extract(smart_mp input1.osm output-smart.osm "-s smart -S types=multipolygon") check_extract(smart_any input1.osm output-smart.osm "-s smart -S types=any") check_extract(smart_nonmp input1.osm output-smart-nonmp.osm "-s smart -S types=x") check_extract_cfg(simple input1.osm output-simple.osm "-s simple") #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/extract/config.json000066400000000000000000000002171315004223400205670ustar00rootroot00000000000000{ "extracts": [ { "output": "-", "output_format": "osm", "description": "Test", "bbox": [0,0,1.5,10] } ] } osmium-tool-1.7.1/test/extract/empty-root.geojson000066400000000000000000000000031315004223400221250ustar00rootroot00000000000000{} osmium-tool-1.7.1/test/extract/empty.geojson000066400000000000000000000000001315004223400211410ustar00rootroot00000000000000osmium-tool-1.7.1/test/extract/empty.osm.opl000066400000000000000000000000001315004223400210640ustar00rootroot00000000000000osmium-tool-1.7.1/test/extract/empty.poly000066400000000000000000000000001315004223400204600ustar00rootroot00000000000000osmium-tool-1.7.1/test/extract/input1.osm000066400000000000000000000043451315004223400203750ustar00rootroot00000000000000 osmium-tool-1.7.1/test/extract/invalid-root.geojson000066400000000000000000000000051315004223400224170ustar00rootroot00000000000000null osmium-tool-1.7.1/test/extract/invalid.geojson000066400000000000000000000000071315004223400214400ustar00rootroot00000000000000FOOBAR osmium-tool-1.7.1/test/extract/missing-end-polygon.poly000066400000000000000000000000741315004223400232370ustar00rootroot00000000000000foo 1 10.0 10.0 19.0 10.0 19.0 19.0 10.0 19.0 10.0 10.0 END osmium-tool-1.7.1/test/extract/missing-end-ring.poly000066400000000000000000000000701315004223400225030ustar00rootroot00000000000000foo 1 10.0 10.0 19.0 10.0 19.0 19.0 10.0 19.0 10.0 10.0 osmium-tool-1.7.1/test/extract/multipolygon.osm.opl000066400000000000000000000005121315004223400225000ustar00rootroot00000000000000n10 x10.0 y10.0 n11 x19.0 y10.0 n12 x19.0 y19.0 n13 x10.0 y19.0 n14 x11.0 y11.0 n15 x18.0 y11.0 n16 x18.0 y18.0 n17 x11.0 y18.0 n20 x20.0 y20.0 n21 x29.0 y20.0 n22 x29.0 y29.0 n23 x20.0 y29.0 w40 Nn10,n11,n12,n13,n10 w41 Nn14,n15,n16,n17,n14 w42 Nn20,n21,n22,n23,n20 r90 Ttype=multipolygon Mw40@,w41@ r91 Ttype=multipolygon Mw42@ osmium-tool-1.7.1/test/extract/no-polygon.osm.opl000066400000000000000000000001251315004223400220370ustar00rootroot00000000000000n10 x10.0 y10.0 n11 x19.0 y10.0 n12 x19.0 y19.0 n13 x10.0 y19.0 w40 Nn10,n11,n12,n13 osmium-tool-1.7.1/test/extract/one-line.poly000066400000000000000000000000041315004223400210340ustar00rootroot00000000000000foo osmium-tool-1.7.1/test/extract/output-complete-ways.osm000066400000000000000000000030711315004223400232770ustar00rootroot00000000000000 osmium-tool-1.7.1/test/extract/output-simple.osm000066400000000000000000000022061315004223400217760ustar00rootroot00000000000000 osmium-tool-1.7.1/test/extract/output-smart-nonmp.osm000066400000000000000000000030711315004223400227610ustar00rootroot00000000000000 osmium-tool-1.7.1/test/extract/output-smart.osm000066400000000000000000000037041315004223400216370ustar00rootroot00000000000000 osmium-tool-1.7.1/test/extract/polygon-crlf.poly000066400000000000000000000001111315004223400217400ustar00rootroot00000000000000foo 1 10.0 10.0 19.0 10.0 19.0 19.0 10.0 19.0 10.0 10.0 END END osmium-tool-1.7.1/test/extract/polygon-one-outer.poly000066400000000000000000000001001315004223400227250ustar00rootroot00000000000000foo 1 10.0 10.0 19.0 10.0 19.0 19.0 10.0 19.0 10.0 10.0 END END osmium-tool-1.7.1/test/extract/polygon-outer-inner.poly000066400000000000000000000001721315004223400232700ustar00rootroot00000000000000foo 1 10.0 10.0 19.0 10.0 19.0 19.0 10.0 19.0 10.0 10.0 END !1s 11.0 11.0 18.0 11.0 18.0 18.0 11.0 18.0 11.0 11.0 END END osmium-tool-1.7.1/test/extract/polygon-two-outer.poly000066400000000000000000000001701315004223400227640ustar00rootroot00000000000000foo 1 10.0 10.0 19.0 10.0 19.0 19.0 10.0 19.0 10.0 10.0 END 2 20.0 20.0 29.0 20.0 29.0 29.0 20.0 29.0 20.0 20.0 END END osmium-tool-1.7.1/test/extract/polygon-two-ways.osm.opl000066400000000000000000000002621315004223400232170ustar00rootroot00000000000000n10 x10.0 y10.0 n11 x19.0 y10.0 n12 x19.0 y19.0 n13 x10.0 y19.0 n20 x20.0 y20.0 n21 x29.0 y20.0 n22 x29.0 y29.0 n23 x20.0 y29.0 w40 Nn10,n11,n12,n13,n10 w41 Nn20,n21,n22,n23,n20 osmium-tool-1.7.1/test/extract/polygon-way.osm.opl000066400000000000000000000001311315004223400222200ustar00rootroot00000000000000n10 x10.0 y10.0 n11 x19.0 y10.0 n12 x19.0 y19.0 n13 x10.0 y19.0 w40 Nn10,n11,n12,n13,n10 osmium-tool-1.7.1/test/extract/test_unit.cpp000066400000000000000000000210071315004223400211510ustar00rootroot00000000000000 #include "test.hpp" // IWYU pragma: keep #include #include "exception.hpp" #include "poly_file_parser.hpp" #include "osm_file_parser.hpp" #include "geojson_file_parser.hpp" TEST_CASE("Parse poly files") { osmium::memory::Buffer buffer{1024}; SECTION("Missing file") { REQUIRE_THROWS(PolyFileParser(buffer, "test/extract/missing.poly")()); } SECTION("Empty file") { PolyFileParser parser{buffer, "test/extract/empty.poly"}; REQUIRE_THROWS_AS(parser(), poly_error); } SECTION("One line file") { PolyFileParser parser{buffer, "test/extract/one-line.poly"}; REQUIRE_THROWS_AS(parser(), poly_error); } SECTION("Two line file") { PolyFileParser parser{buffer, "test/extract/two-line.poly"}; REQUIRE_THROWS_AS(parser(), poly_error); } SECTION("Missing END ring") { PolyFileParser parser{buffer, "test/extract/missing-end-ring.poly"}; REQUIRE_THROWS_AS(parser(), poly_error); } SECTION("Missing END polygon") { PolyFileParser parser{buffer, "test/extract/missing-end-polygon.poly"}; REQUIRE_THROWS_AS(parser(), poly_error); } SECTION("File with one polygon with one outer ring") { PolyFileParser parser{buffer, "test/extract/polygon-one-outer.poly"}; REQUIRE(parser() == 0); const osmium::Area& area = buffer.get(0); const auto nr = area.num_rings(); REQUIRE(nr.first == 1); REQUIRE(nr.second == 0); auto it = area.outer_rings().begin(); REQUIRE(it != area.outer_rings().end()); REQUIRE(it->front().location() == osmium::Location(10.0, 10.0)); ++it; REQUIRE(it == area.outer_rings().end()); } SECTION("File with one polygons with two outer rings") { PolyFileParser parser{buffer, "test/extract/polygon-two-outer.poly"}; REQUIRE(parser() == 0); const osmium::Area& area = buffer.get(0); const auto nr = area.num_rings(); REQUIRE(nr.first == 2); REQUIRE(nr.second == 0); auto it = area.outer_rings().begin(); REQUIRE(it != area.outer_rings().end()); REQUIRE(it->front().location() == osmium::Location(10.0, 10.0)); ++it; REQUIRE(it != area.outer_rings().end()); REQUIRE(it->front().location() == osmium::Location(20.0, 20.0)); ++it; REQUIRE(it == area.outer_rings().end()); } SECTION("File with one polygon with outer and inner rings") { PolyFileParser parser{buffer, "test/extract/polygon-outer-inner.poly"}; REQUIRE(parser() == 0); const osmium::Area& area = buffer.get(0); const auto nr = area.num_rings(); REQUIRE(nr.first == 1); REQUIRE(nr.second == 1); auto it = area.outer_rings().begin(); REQUIRE(it != area.outer_rings().end()); REQUIRE(it->front().location() == osmium::Location(10.0, 10.0)); const auto& inner_ring = *area.inner_rings(*it).begin(); REQUIRE(inner_ring.front().location() == osmium::Location(11.0, 11.0)); ++it; REQUIRE(it == area.outer_rings().end()); } SECTION("Two concatenated files") { PolyFileParser parser{buffer, "test/extract/two-polygons.poly"}; REQUIRE(parser() == 0); const osmium::Area& area = buffer.get(0); const auto nr = area.num_rings(); REQUIRE(nr.first == 2); REQUIRE(nr.second == 1); auto it = area.outer_rings().begin(); REQUIRE(it != area.outer_rings().end()); REQUIRE(it->front().location() == osmium::Location(10.0, 10.0)); const auto& inner_ring = *area.inner_rings(*it).begin(); REQUIRE(inner_ring.front().location() == osmium::Location(11.0, 11.0)); ++it; REQUIRE(it != area.outer_rings().end()); REQUIRE(it->front().location() == osmium::Location(20.0, 20.0)); ++it; REQUIRE(it == area.outer_rings().end()); } SECTION("Two concatenated files with empty line in between") { PolyFileParser parser{buffer, "test/extract/two-polygons-empty-line.poly"}; REQUIRE(parser() == 0); const osmium::Area& area = buffer.get(0); const auto nr = area.num_rings(); REQUIRE(nr.first == 2); REQUIRE(nr.second == 1); } } TEST_CASE("Parse OSM files") { osmium::memory::Buffer buffer{1024}; SECTION("Missing OSM file") { REQUIRE_THROWS(OSMFileParser(buffer, "test/extract/missing.osm.opl")()); } SECTION("Empty OSM file") { OSMFileParser parser{buffer, "test/extract/empty.osm.opl"}; REQUIRE_THROWS(parser()); } SECTION("OSM file without polygon") { OSMFileParser parser{buffer, "test/extract/no-polygon.osm.opl"}; REQUIRE_THROWS(parser()); } SECTION("OSM file with simple polygon") { OSMFileParser parser{buffer, "test/extract/polygon-way.osm.opl"}; REQUIRE(parser() == 0); const osmium::Area& area = buffer.get(0); const auto nr = area.num_rings(); REQUIRE(nr.first == 1); REQUIRE(nr.second == 0); auto it = area.outer_rings().begin(); REQUIRE(it != area.outer_rings().end()); REQUIRE(it->front().location() == osmium::Location(10.0, 10.0)); ++it; REQUIRE(it == area.outer_rings().end()); } SECTION("OSM file with two simple polygons") { OSMFileParser parser{buffer, "test/extract/polygon-two-ways.osm.opl"}; REQUIRE(parser() == 0); const osmium::Area& area = buffer.get(0); const auto nr = area.num_rings(); REQUIRE(nr.first == 2); REQUIRE(nr.second == 0); auto it = area.outer_rings().begin(); REQUIRE(it != area.outer_rings().end()); REQUIRE(it->front().location() == osmium::Location(10.0, 10.0)); ++it; REQUIRE(it != area.outer_rings().end()); REQUIRE(it->front().location() == osmium::Location(20.0, 20.0)); ++it; REQUIRE(it == area.outer_rings().end()); } SECTION("OSM file with multipolygon relation") { OSMFileParser parser{buffer, "test/extract/multipolygon.osm.opl"}; REQUIRE(parser() == 0); const osmium::Area& area = buffer.get(0); const auto nr = area.num_rings(); REQUIRE(nr.first == 2); REQUIRE(nr.second == 1); auto it = area.outer_rings().begin(); REQUIRE(it != area.outer_rings().end()); REQUIRE(it->front().location() == osmium::Location(10.0, 10.0)); const auto& inner_ring = *area.inner_rings(*it).begin(); REQUIRE(inner_ring.front().location() == osmium::Location(11.0, 11.0)); ++it; REQUIRE(it != area.outer_rings().end()); REQUIRE(it->front().location() == osmium::Location(20.0, 20.0)); ++it; REQUIRE(it == area.outer_rings().end()); } SECTION("File with CRLF") { PolyFileParser parser{buffer, "test/extract/polygon-crlf.poly"}; REQUIRE(parser() == 0); const osmium::Area& area = buffer.get(0); const auto nr = area.num_rings(); REQUIRE(nr.first == 1); REQUIRE(nr.second == 0); auto it = area.outer_rings().begin(); REQUIRE(it != area.outer_rings().end()); REQUIRE(it->front().location() == osmium::Location(10.0, 10.0)); ++it; REQUIRE(it == area.outer_rings().end()); } } TEST_CASE("Parse GeoJSON files") { osmium::memory::Buffer buffer{1024}; SECTION("Missing GeoJSON file") { REQUIRE_THROWS(GeoJSONFileParser(buffer, "test/extract/missing.geojson")()); } SECTION("Empty GeoJSON file") { GeoJSONFileParser parser{buffer, "test/extract/empty.geojson"}; REQUIRE_THROWS(parser()); } SECTION("Invalid GeoJSON file") { GeoJSONFileParser parser{buffer, "test/extract/invalid.geojson"}; REQUIRE_THROWS_AS(parser(), geojson_error); } SECTION("Invalid GeoJSON file: Root not an object") { GeoJSONFileParser parser{buffer, "test/extract/invalid-root.geojson"}; REQUIRE_THROWS_AS(parser(), geojson_error); } SECTION("Invalid GeoJSON file: Empty root object") { GeoJSONFileParser parser{buffer, "test/extract/empty-root.geojson"}; REQUIRE_THROWS_AS(parser(), geojson_error); } SECTION("Invalid GeoJSON file: Wrong geometry type") { GeoJSONFileParser parser{buffer, "test/extract/wrong-geometry-type.geojson"}; REQUIRE_THROWS_AS(parser(), geojson_error); } } osmium-tool-1.7.1/test/extract/two-line.poly000066400000000000000000000000101315004223400210610ustar00rootroot00000000000000foo bar osmium-tool-1.7.1/test/extract/two-polygons-empty-line.poly000066400000000000000000000002731315004223400241000ustar00rootroot00000000000000foo 1 10.0 10.0 19.0 10.0 19.0 19.0 10.0 19.0 10.0 10.0 END !1s 11.0 11.0 18.0 11.0 18.0 18.0 11.0 18.0 11.0 11.0 END END bar 2 20.0 20.0 29.0 20.0 29.0 29.0 20.0 29.0 20.0 20.0 END END osmium-tool-1.7.1/test/extract/two-polygons.poly000066400000000000000000000002721315004223400220160ustar00rootroot00000000000000foo 1 10.0 10.0 19.0 10.0 19.0 19.0 10.0 19.0 10.0 10.0 END !1s 11.0 11.0 18.0 11.0 18.0 18.0 11.0 18.0 11.0 11.0 END END bar 2 20.0 20.0 29.0 20.0 29.0 29.0 20.0 29.0 20.0 20.0 END END osmium-tool-1.7.1/test/extract/wrong-geometry-type.geojson000066400000000000000000000001131315004223400237540ustar00rootroot00000000000000{ "type": "Feature", "geometry": { "type": "Point" } } osmium-tool-1.7.1/test/fileinfo/000077500000000000000000000000001315004223400165505ustar00rootroot00000000000000osmium-tool-1.7.1/test/fileinfo/CMakeLists.txt000066400000000000000000000023051315004223400213100ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - fileinfo # #----------------------------------------------------------------------------- function(check_fileinfo _name _options _input _output) check_output(fileinfo ${_name} "fileinfo ${_options} fileinfo/${_input}" "fileinfo/${_output}") endfunction() #----------------------------------------------------------------------------- check_fileinfo(fi1-extended "--extended" fi1.osm fi1-result.txt) add_test(NAME fileinfo-g-generator COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi1.osm -g header.option.generator) set_tests_properties(fileinfo-g-generator PROPERTIES PASS_REGULAR_EXPRESSION "^testdata\n$") add_test(NAME fileinfo-g-unknown-option COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi1.osm -g header.option.foo) set_tests_properties(fileinfo-g-unknown-option PROPERTIES PASS_REGULAR_EXPRESSION "^$") add_test(NAME fileinfo-g-fail COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi1.osm -g foobar) set_tests_properties(fileinfo-g-fail PROPERTIES WILL_FAIL true) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/fileinfo/fi1-result.txt000066400000000000000000000010621315004223400213030ustar00rootroot00000000000000File: Name: fileinfo/fi1.osm Format: XML Compression: none Size: 438 Header: Bounding boxes: With history: no Options: generator=testdata version=0.6 Data: Bounding box: (1,1,1,3) Timestamps: First: 2015-01-01T01:00:00Z Last: 2015-01-01T04:00:00Z Objects ordered (by type and id): yes Multiple versions of same object: no CRC32: 8e178104 Number of changesets: 0 Number of nodes: 3 Number of ways: 0 Number of relations: 0 Largest changeset ID: 0 Largest node ID: 4 Largest way ID: 0 Largest relation ID: 0 osmium-tool-1.7.1/test/fileinfo/fi1.osm000066400000000000000000000006661315004223400177570ustar00rootroot00000000000000 osmium-tool-1.7.1/test/formats/000077500000000000000000000000001315004223400164305ustar00rootroot00000000000000osmium-tool-1.7.1/test/formats/CMakeLists.txt000066400000000000000000000056301315004223400211740ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - formats # #----------------------------------------------------------------------------- function(check_formats _name _input _format _output) check_output(formats ${_name} "cat --generator=test --output-header xml_josm_upload=false -f ${_format} ${PROJECT_SOURCE_DIR}/test/formats/${_input}" "formats/${_output}") endfunction() #----------------------------------------------------------------------------- # empty file (no objects) check_formats(emptyxx empty.osm xml empty.osm) check_formats(emptyxo empty.osm opl empty.osm.opl) check_formats(emptyxp empty.osm pbf empty.osm.pbf) check_formats(emptyxpd empty.osm pbf,pbf_dense_nodes=false empty-nodensenodes.osm.pbf) check_formats(emptyxpc empty.osm pbf,pbf_compression=none empty-nocompression.osm.pbf) check_formats(emptyxpm empty.osm pbf,pbf_add_metadata=false empty-nometadata.osm.pbf) check_formats(emptyxpdm empty.osm pbf,pbf_dense_nodes=false,add_metadata=false empty-nodensenodes-nometadata.osm.pbf) check_formats(emptypx empty.osm.pbf xml empty.osm) check_formats(emptypo empty.osm.pbf opl empty.osm.opl) check_formats(emptypp empty.osm.pbf pbf empty.osm.pbf) check_formats(emptypxd empty-nodensenodes.osm.pbf xml empty.osm) check_formats(emptypod empty-nodensenodes.osm.pbf opl empty.osm.opl) check_formats(emptyppd empty-nodensenodes.osm.pbf pbf empty.osm.pbf) check_formats(emptypxc empty-nocompression.osm.pbf xml empty.osm) check_formats(emptypoc empty-nocompression.osm.pbf opl empty.osm.opl) check_formats(emptyppc empty-nocompression.osm.pbf pbf empty.osm.pbf) # normal file check_formats(f1xx f1.osm xml f1.osm) check_formats(f1xo f1.osm opl f1.osm.opl) check_formats(f1xp f1.osm pbf f1.osm.pbf) check_formats(f1xpd f1.osm pbf,pbf_dense_nodes=false f1-nodensenodes.osm.pbf) check_formats(f1xpc f1.osm pbf,pbf_compression=none f1-nocompression.osm.pbf) check_formats(f1xpm f1.osm pbf,add_metadata=false f1-nometadata.osm.pbf) check_formats(f1xpdm f1.osm pbf,pbf_dense_nodes=false,pbf_add_metadata=false f1-nodensenodes-nometadata.osm.pbf) check_formats(f1px f1.osm.pbf xml f1.osm) check_formats(f1po f1.osm.pbf opl f1.osm.opl) check_formats(f1pp f1.osm.pbf pbf f1.osm.pbf) check_formats(f1pxd f1-nodensenodes.osm.pbf xml f1.osm) check_formats(f1pod f1-nodensenodes.osm.pbf opl f1.osm.opl) check_formats(f1ppd f1-nodensenodes.osm.pbf pbf f1.osm.pbf) check_formats(f1pxc f1-nocompression.osm.pbf xml f1.osm) check_formats(f1poc f1-nocompression.osm.pbf opl f1.osm.opl) check_formats(f1ppc f1-nocompression.osm.pbf pbf f1.osm.pbf) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/formats/empty-nocompression.osm.pbf000066400000000000000000000000661315004223400237520ustar00rootroot00000000000000 OSMHeader% #"OsmSchema-V0.6" DenseNodes‚testosmium-tool-1.7.1/test/formats/empty-nodensenodes-nometadata.osm.pbf000066400000000000000000000000641315004223400256510ustar00rootroot00000000000000 OSMHeader#xœSâó/Î NÎHÍMÔ 3Ð3kbd)I-.R›osmium-tool-1.7.1/test/formats/empty-nodensenodes.osm.pbf000066400000000000000000000000641315004223400235360ustar00rootroot00000000000000 OSMHeader#xœSâó/Î NÎHÍMÔ 3Ð3kbd)I-.R›osmium-tool-1.7.1/test/formats/empty-nometadata.osm.pbf000066400000000000000000000001001315004223400231560ustar00rootroot00000000000000 OSMHeader/#+xœSâó/Î NÎHÍMÔ 3Ð3SârIÍ+NõËOI-nbd)I-.¿` #osmium-tool-1.7.1/test/formats/empty.osm000066400000000000000000000001421315004223400203030ustar00rootroot00000000000000 osmium-tool-1.7.1/test/formats/empty.osm.opl000066400000000000000000000000001315004223400210650ustar00rootroot00000000000000osmium-tool-1.7.1/test/formats/empty.osm.pbf000066400000000000000000000001001315004223400210430ustar00rootroot00000000000000 OSMHeader/#+xœSâó/Î NÎHÍMÔ 3Ð3SârIÍ+NõËOI-nbd)I-.¿` #osmium-tool-1.7.1/test/formats/f1-nocompression.osm.pbf000066400000000000000000000006041315004223400231200ustar00rootroot00000000000000 OSMHeader% #"OsmSchema-V0.6" DenseNodes‚test OSMDataq o  test foo\Z *+ €ìé³ Àñœ<Þ‡Ò9‚‹Ì "*B€ÚÄ œìî äÇš €ÚÄ J €ÚÄ ð¼Ÿ?R OSMDataf d # foo xyz !@$ bar *#/ test=#"¸’¥ (B"¸’¥ (B OSMDataJ H  xyz abc test some way&"$"¸’¥ (BJRosmium-tool-1.7.1/test/formats/f1-nodensenodes-nometadata.osm.pbf000066400000000000000000000004411315004223400250200ustar00rootroot00000000000000 OSMHeader#xœSâó/Î NÎHÍMÔ 3Ð3kbd)I-.R› OSMData=>9xœãbâb²àâáqh¸u„ÓDybsŽmöø0í 7'áÐÐwN&'åÐðb’˜8o¦ OSMDataG>Cxœã’åbàbNËÏQ•U\ÌŠ*\ÌI‰E\ÌZÊúB²RÂ"B,ŒLÌ,R,¬¬LlNÌ"LLRl¢NLL" OSMData<28xœã’àbàb®¨¬âbNLJ²9ŠósSÊ+…Ä”D8ä„¥™œ˜˜Y¼˜$‚˜éDâosmium-tool-1.7.1/test/formats/f1-nodensenodes.osm.pbf000066400000000000000000000006221315004223400227060ustar00rootroot00000000000000 OSMHeader#xœSâó/Î NÎHÍMÔ 3Ð3kbd)I-.R› OSMData|‹wxœãâçbàb)I-.ÒÌiùùB\2"J|Œ ß¾Üd‘`T`Ô`th¸u„ÓDeÅÀ²Ö5ÿÉ2h09Ì9¶YØãô'Ü@Y °ìùMo¦°J0)0k0;4ô“é•ËNØ1i)«3Ää“ÔÀ²â<&ñ OSMDatabd^xœãRæbàbNËÏQ•U\ÌŠ*\ÌI‰E\ÌZÊú\,%©Å%B¶RÊ"B,ŒLÌ,R,¬¬LlJ|ŒvLZÊ*Á¢À¨ÁîÄ,ÂÄ$%Æ!Š$Á–`’`,¦¥ OSMDataSHOxœã’ãbàb®¨¬âbNLJæb)I-.Špçç¦*”'V ©)©pÈ 12J12)ñq0 LØ1i)«££³ «“„@# osmium-tool-1.7.1/test/formats/f1-nometadata.osm.pbf000066400000000000000000000004531315004223400223410ustar00rootroot00000000000000 OSMHeader/#+xœSâó/Î NÎHÍMÔ 3Ð3SârIÍ+NõËOI-nbd)I-.¿` # OSMData;57xœãbâbÒÒåbabbrh¸u„sΛwœOŽÏâ±½xAä‡=ó™Þ1C §™ OSMDataG>Cxœã’åbàbNËÏQ•U\ÌŠ*\ÌI‰E\ÌZÊúB²RÂ"B,ŒLÌ,R,¬¬LlNÌ"LLRl¢NLL" OSMData<28xœã’àbàb®¨¬âbNLJ²9ŠósSÊ+…Ä”D8ä„¥™œ˜˜Y¼˜$‚˜éDâosmium-tool-1.7.1/test/formats/f1.osm000066400000000000000000000022341315004223400174570ustar00rootroot00000000000000 osmium-tool-1.7.1/test/formats/f1.osm.opl000066400000000000000000000006601315004223400202510ustar00rootroot00000000000000n10 v1 dV c1 t2010-01-01T00:00:00Z i1 utest T x1 y1 n11 v1 dV c1 t2012-01-01T22:00:00Z i0 u T x1.2355 y2.034523 n12 v1 dV c2 t2013-12-01T11:11:11Z i3 ufoo T x1 y3 n13 v1 dV c3 t2015-01-01T01:00:00Z i1 utest T x1 y4 w20 v1 dV c4 t2015-01-01T01:00:00Z i1 utest Tfoo=bar,=bar,xyz=,!%40%$=*#/ Nn10,n11,n12 w21 v1 dV c1 t2015-01-01T01:00:00Z i1 utest T Nn12,n13 r30 v1 dV c1 t2015-01-01T01:00:00Z i1 utest Txyz=abc Mn12@,w20@some%20%way osmium-tool-1.7.1/test/formats/f1.osm.pbf000066400000000000000000000006241315004223400202260ustar00rootroot00000000000000 OSMHeader/#+xœSâó/Î NÎHÍMÔ 3Ð3SârIÍ+NõËOI-nbd)I-.¿` # OSMDataronxœãâçbàb)I-.ÒÌiùùB1BQ\,"LLLZÚ\,Œ@ $ØðæåfÎçØÜk¿dÙÔ}FAŠ…‰‰I‰…‰‘Y‹¨–ÙI áÖÎ9oÞq>9>‹Äöâ‘öÌgzÄ A, @= C OSMDatabd^xœãRæbàbNËÏQ•U\ÌŠ*\ÌI‰E\ÌZÊú\,%©Å%B¶RÊ"B,ŒLÌ,R,¬¬LlJ|ŒvLZÊ*Á¢À¨ÁîÄ,ÂÄ$%Æ!Š$Á–`’`,¦¥ OSMDataSHOxœã’ãbàb®¨¬âbNLJæb)I-.Špçç¦*”'V ©)©pÈ 12J12)ñq0 LØ1i)«££³ «“„@# osmium-tool-1.7.1/test/getid/000077500000000000000000000000001315004223400160515ustar00rootroot00000000000000osmium-tool-1.7.1/test/getid/CMakeLists.txt000066400000000000000000000041161315004223400206130ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - getid # #----------------------------------------------------------------------------- function(check_getid _name _input _output) check_output(getid ${_name} "getid --generator=test -f osm getid/${_input} n11,n12 w21" "getid/${_output}") endfunction() function(check_getid_file _name _file _input _output) check_output(getid ${_name} "getid --generator=test -i getid/${_file} -f osm getid/${_input}" "getid/${_output}") endfunction() check_getid(n input.osm output.osm) check_getid_file(file1 idfile input.osm output-file.osm) #----------------------------------------------------------------------------- function(check_getid_r _name _source _input _output) check_output(getid ${_name} "getid -r --generator=test -f osm getid/${_source}.osm -I getid/${_input}.osm" "getid/${_output}.osm") check_output(getid ${_name}-i "getid -r --generator=test -f osm getid/${_source}.osm -i getid/${_input}.id" "getid/${_output}.osm") endfunction() check_getid_r(n10 source in10 out10) check_getid_r(w21 source in21 out21) check_getid_r(r30 source in30 out30) check_getid_r(r31 source in31 out31) check_getid_r(r32 source in32 out32) check_getid_r(n10nrr source-no-rr in10 out10) check_getid_r(w21nrr source-no-rr in21 out21) check_getid_r(r30nrr source-no-rr in30 out30) check_getid_r(r32nrr source-no-rr in32 out32) check_getid_r(missing-n19 source in19 out31) set_tests_properties(getid-missing-n19 PROPERTIES WILL_FAIL true) set_tests_properties(getid-missing-n19-i PROPERTIES WILL_FAIL true) check_getid_r(missing-w29 source in29 out31) set_tests_properties(getid-missing-w29 PROPERTIES WILL_FAIL true) set_tests_properties(getid-missing-w29-i PROPERTIES WILL_FAIL true) check_getid_r(missing-r39 source in39 out31) set_tests_properties(getid-missing-r39 PROPERTIES WILL_FAIL true) set_tests_properties(getid-missing-r39-i PROPERTIES WILL_FAIL true) check_getid_r(relloop relloop relloop relloop-out) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/getid/idfile000066400000000000000000000000741315004223400172310ustar00rootroot00000000000000n11 n12 foo n10 n13 # comment # comment w21 osmium-tool-1.7.1/test/getid/in10.id000066400000000000000000000000041315004223400171300ustar00rootroot00000000000000n10 osmium-tool-1.7.1/test/getid/in10.osm000066400000000000000000000003271315004223400173420ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/in19.id000066400000000000000000000000041315004223400171410ustar00rootroot00000000000000n19 osmium-tool-1.7.1/test/getid/in19.osm000066400000000000000000000003271315004223400173530ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/in21.id000066400000000000000000000000041315004223400171320ustar00rootroot00000000000000w21 osmium-tool-1.7.1/test/getid/in21.osm000066400000000000000000000003641315004223400173450ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/in29.id000066400000000000000000000000041315004223400171420ustar00rootroot00000000000000w29 osmium-tool-1.7.1/test/getid/in29.osm000066400000000000000000000003641315004223400173550ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/in30.id000066400000000000000000000000041315004223400171320ustar00rootroot00000000000000r30 osmium-tool-1.7.1/test/getid/in30.osm000066400000000000000000000005271315004223400173460ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/in31.id000066400000000000000000000000041315004223400171330ustar00rootroot00000000000000r31 osmium-tool-1.7.1/test/getid/in31.osm000066400000000000000000000004071315004223400173440ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/in32.id000066400000000000000000000000041315004223400171340ustar00rootroot00000000000000r32 osmium-tool-1.7.1/test/getid/in32.osm000066400000000000000000000004031315004223400173410ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/in39.id000066400000000000000000000000041315004223400171430ustar00rootroot00000000000000r39 osmium-tool-1.7.1/test/getid/in39.osm000066400000000000000000000004031315004223400173500ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/input.osm000066400000000000000000000021321315004223400177260ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/out10.osm000066400000000000000000000003041315004223400175360ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/out21.osm000066400000000000000000000007031315004223400175430ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/out30.osm000066400000000000000000000016631315004223400175510ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/out31.osm000066400000000000000000000021241315004223400175430ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/out32.osm000066400000000000000000000005411315004223400175450ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/output-file.osm000066400000000000000000000013001315004223400210400ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/output.osm000066400000000000000000000007361315004223400201370ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/relloop-out.osm000066400000000000000000000006251315004223400210550ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/relloop.id000066400000000000000000000000101315004223400200320ustar00rootroot00000000000000r30 r31 osmium-tool-1.7.1/test/getid/relloop.osm000066400000000000000000000006501315004223400202460ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/source-no-rr.osm000066400000000000000000000025421315004223400211270ustar00rootroot00000000000000 osmium-tool-1.7.1/test/getid/source.osm000066400000000000000000000030031315004223400200650ustar00rootroot00000000000000 osmium-tool-1.7.1/test/help/000077500000000000000000000000001315004223400157055ustar00rootroot00000000000000osmium-tool-1.7.1/test/help/CMakeLists.txt000066400000000000000000000012211315004223400204410ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - help # #----------------------------------------------------------------------------- do_test(help1 "osmium" "^Usage: .*COMMANDS:") do_test(help2 "osmium help" "^Usage: .*COMMANDS:") do_test(help3 "osmium --help" "^Usage: .*COMMANDS:") do_test(help4 "osmium -h" "^Usage: .*COMMANDS:") if(PANDOC) do_test(help_cat "osmium help cat" "^OSMIUM-CAT\\(1\\)") endif() do_test(help_topic_unknown "osmium help x" "^Unknown help topic 'x'.\n") #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/include/000077500000000000000000000000001315004223400164005ustar00rootroot00000000000000osmium-tool-1.7.1/test/include/catch.hpp000066400000000000000000014721131315004223400202040ustar00rootroot00000000000000/* * Catch v1.9.7 * Generated: 2017-08-10 23:49:15.233907 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_CATCH_HPP_INCLUDED #ifdef __clang__ # pragma clang system_header #elif defined __GNUC__ # pragma GCC system_header #endif // #included from: internal/catch_suppress_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(push) # pragma warning(disable: 161 1682) # else // __ICC # pragma clang diagnostic ignored "-Wglobal-constructors" # pragma clang diagnostic ignored "-Wvariadic-macros" # pragma clang diagnostic ignored "-Wc99-extensions" # pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wc++98-compat" # pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wvariadic-macros" # pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wparentheses" # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpadded" #endif #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL #endif #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED # define CLARA_CONFIG_MAIN # endif #endif // #included from: internal/catch_notimplemented_exception.h #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED // #included from: catch_common.h #define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED // #included from: catch_compiler_capabilities.h #define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED // Detect a number of compiler features - mostly C++11/14 conformance - by compiler // The following features are defined: // // CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? // CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? // CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods // CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? // CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported // CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? // CATCH_CONFIG_CPP11_OVERRIDE : is override supported? // CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) // CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported? // CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported? // CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? // CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too // **************** // In general each macro has a _NO_ form // (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. // All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 #ifdef __cplusplus # if __cplusplus >= 201103L # define CATCH_CPP11_OR_GREATER # endif # if __cplusplus >= 201402L # define CATCH_CPP14_OR_GREATER # endif #endif #ifdef __clang__ # if __has_feature(cxx_nullptr) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif # if __has_feature(cxx_noexcept) # define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # endif # if defined(CATCH_CPP11_OR_GREATER) # define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ _Pragma( "clang diagnostic push" ) \ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) # define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ _Pragma( "clang diagnostic pop" ) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic push" ) \ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic pop" ) # endif #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// // We know some environments not to support full POSIX signals #if defined(__CYGWIN__) || defined(__QNX__) # if !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS # endif #endif #ifdef __OS400__ # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS # define CATCH_CONFIG_COLOUR_NONE #endif //////////////////////////////////////////////////////////////////////////////// // Cygwin #ifdef __CYGWIN__ // Required for some versions of Cygwin to declare gettimeofday // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin # define _BSD_SOURCE #endif // __CYGWIN__ //////////////////////////////////////////////////////////////////////////////// // Borland #ifdef __BORLANDC__ #endif // __BORLANDC__ //////////////////////////////////////////////////////////////////////////////// // EDG #ifdef __EDG_VERSION__ #endif // __EDG_VERSION__ //////////////////////////////////////////////////////////////////////////////// // Digital Mars #ifdef __DMC__ #endif // __DMC__ //////////////////////////////////////////////////////////////////////////////// // GCC #ifdef __GNUC__ # if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif // - otherwise more recent versions define __cplusplus >= 201103L // and will get picked up below #endif // __GNUC__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ #ifdef _MSC_VER #define CATCH_INTERNAL_CONFIG_WINDOWS_SEH #if (_MSC_VER >= 1600) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR #endif #if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) #define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT #define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS #define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE #define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS #endif #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// // Use variadic macros if the compiler supports them #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ ( defined __GNUC__ && __GNUC__ >= 3 ) || \ ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) #define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS #endif // Use __COUNTER__ if the compiler supports it #if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \ ( defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \ ( defined __clang__ && __clang_major__ >= 3 ) #define CATCH_INTERNAL_CONFIG_COUNTER #endif //////////////////////////////////////////////////////////////////////////////// // C++ language feature support // catch all support for C++11 #if defined(CATCH_CPP11_OR_GREATER) # if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS # define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM # define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE # define CATCH_INTERNAL_CONFIG_CPP11_TUPLE # endif # ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS # define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS # endif # if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) # define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG # endif # if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) # define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE # endif # if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) # define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR # endif # if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) # define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE # endif # if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) # define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS # endif #endif // __cplusplus >= 201103L // Now set the actual defines based on the above + anything the user has configured #if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_NULLPTR #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_NOEXCEPT #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_GENERATED_METHODS #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_IS_ENUM #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_TUPLE #endif #if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) # define CATCH_CONFIG_VARIADIC_MACROS #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_LONG_LONG #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_OVERRIDE #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_UNIQUE_PTR #endif // Use of __COUNTER__ is suppressed if __JETBRAINS_IDE__ is #defined (meaning we're being parsed by a JetBrains IDE for // analytics) because, at time of writing, __COUNTER__ is not properly handled by it. // This does not affect compilation #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) && !defined(__JETBRAINS_IDE__) # define CATCH_CONFIG_COUNTER #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_SHUFFLE #endif # if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_TYPE_TRAITS # endif #if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) # define CATCH_CONFIG_WINDOWS_SEH #endif // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. #if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_CONFIG_POSIX_SIGNALS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS #endif // noexcept support: #if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) # define CATCH_NOEXCEPT noexcept # define CATCH_NOEXCEPT_IS(x) noexcept(x) #else # define CATCH_NOEXCEPT throw() # define CATCH_NOEXCEPT_IS(x) #endif // nullptr support #ifdef CATCH_CONFIG_CPP11_NULLPTR # define CATCH_NULL nullptr #else # define CATCH_NULL NULL #endif // override support #ifdef CATCH_CONFIG_CPP11_OVERRIDE # define CATCH_OVERRIDE override #else # define CATCH_OVERRIDE #endif // unique_ptr support #ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR # define CATCH_AUTO_PTR( T ) std::unique_ptr #else # define CATCH_AUTO_PTR( T ) std::auto_ptr #endif #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #ifdef CATCH_CONFIG_COUNTER # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) #else # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #endif #define INTERNAL_CATCH_STRINGIFY2( expr ) #expr #define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) #include #include namespace Catch { struct IConfig; struct CaseSensitive { enum Choice { Yes, No }; }; class NonCopyable { #ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; NonCopyable& operator = ( NonCopyable && ) = delete; #else NonCopyable( NonCopyable const& info ); NonCopyable& operator = ( NonCopyable const& ); #endif protected: NonCopyable() {} virtual ~NonCopyable(); }; class SafeBool { public: typedef void (SafeBool::*type)() const; static type makeSafe( bool value ) { return value ? &SafeBool::trueValue : 0; } private: void trueValue() const {} }; template void deleteAll( ContainerT& container ) { typename ContainerT::const_iterator it = container.begin(); typename ContainerT::const_iterator itEnd = container.end(); for(; it != itEnd; ++it ) delete *it; } template void deleteAllValues( AssociativeContainerT& container ) { typename AssociativeContainerT::const_iterator it = container.begin(); typename AssociativeContainerT::const_iterator itEnd = container.end(); for(; it != itEnd; ++it ) delete it->second; } bool startsWith( std::string const& s, std::string const& prefix ); bool startsWith( std::string const& s, char prefix ); bool endsWith( std::string const& s, std::string const& suffix ); bool endsWith( std::string const& s, char suffix ); bool contains( std::string const& s, std::string const& infix ); void toLowerInPlace( std::string& s ); std::string toLower( std::string const& s ); std::string trim( std::string const& str ); bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); struct pluralise { pluralise( std::size_t count, std::string const& label ); friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); std::size_t m_count; std::string m_label; }; struct SourceLineInfo { SourceLineInfo(); SourceLineInfo( char const* _file, std::size_t _line ); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS SourceLineInfo(SourceLineInfo const& other) = default; SourceLineInfo( SourceLineInfo && ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo& operator = ( SourceLineInfo && ) = default; # endif bool empty() const; bool operator == ( SourceLineInfo const& other ) const; bool operator < ( SourceLineInfo const& other ) const; char const* file; std::size_t line; }; std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); // This is just here to avoid compiler warnings with macro constants and boolean literals inline bool isTrue( bool value ){ return value; } inline bool alwaysTrue() { return true; } inline bool alwaysFalse() { return false; } void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); void seedRng( IConfig const& config ); unsigned int rngSeed(); // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as // >> stuff +StreamEndStop struct StreamEndStop { std::string operator+() { return std::string(); } }; template T const& operator + ( T const& value, StreamEndStop ) { return value; } } #define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) #define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); namespace Catch { class NotImplementedException : public std::exception { public: NotImplementedException( SourceLineInfo const& lineInfo ); virtual ~NotImplementedException() CATCH_NOEXCEPT {} virtual const char* what() const CATCH_NOEXCEPT; private: std::string m_what; SourceLineInfo m_lineInfo; }; } // end namespace Catch /////////////////////////////////////////////////////////////////////////////// #define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) // #included from: internal/catch_context.h #define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED // #included from: catch_interfaces_generators.h #define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED #include namespace Catch { struct IGeneratorInfo { virtual ~IGeneratorInfo(); virtual bool moveNext() = 0; virtual std::size_t getCurrentIndex() const = 0; }; struct IGeneratorsForTest { virtual ~IGeneratorsForTest(); virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; virtual bool moveNext() = 0; }; IGeneratorsForTest* createGeneratorsForTest(); } // end namespace Catch // #included from: catch_ptr.hpp #define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif namespace Catch { // An intrusive reference counting smart pointer. // T must implement addRef() and release() methods // typically implementing the IShared interface template class Ptr { public: Ptr() : m_p( CATCH_NULL ){} Ptr( T* p ) : m_p( p ){ if( m_p ) m_p->addRef(); } Ptr( Ptr const& other ) : m_p( other.m_p ){ if( m_p ) m_p->addRef(); } ~Ptr(){ if( m_p ) m_p->release(); } void reset() { if( m_p ) m_p->release(); m_p = CATCH_NULL; } Ptr& operator = ( T* p ){ Ptr temp( p ); swap( temp ); return *this; } Ptr& operator = ( Ptr const& other ){ Ptr temp( other ); swap( temp ); return *this; } void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } T* get() const{ return m_p; } T& operator*() const { return *m_p; } T* operator->() const { return m_p; } bool operator !() const { return m_p == CATCH_NULL; } operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } private: T* m_p; }; struct IShared : NonCopyable { virtual ~IShared(); virtual void addRef() const = 0; virtual void release() const = 0; }; template struct SharedImpl : T { SharedImpl() : m_rc( 0 ){} virtual void addRef() const { ++m_rc; } virtual void release() const { if( --m_rc == 0 ) delete this; } mutable unsigned int m_rc; }; } // end namespace Catch #ifdef __clang__ #pragma clang diagnostic pop #endif namespace Catch { class TestCase; class Stream; struct IResultCapture; struct IRunner; struct IGeneratorsForTest; struct IConfig; struct IContext { virtual ~IContext(); virtual IResultCapture* getResultCapture() = 0; virtual IRunner* getRunner() = 0; virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; virtual bool advanceGeneratorsForCurrentTest() = 0; virtual Ptr getConfig() const = 0; }; struct IMutableContext : IContext { virtual ~IMutableContext(); virtual void setResultCapture( IResultCapture* resultCapture ) = 0; virtual void setRunner( IRunner* runner ) = 0; virtual void setConfig( Ptr const& config ) = 0; }; IContext& getCurrentContext(); IMutableContext& getCurrentMutableContext(); void cleanUpContext(); Stream createStream( std::string const& streamName ); } // #included from: internal/catch_test_registry.hpp #define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED // #included from: catch_interfaces_testcase.h #define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED #include namespace Catch { class TestSpec; struct ITestCase : IShared { virtual void invoke () const = 0; protected: virtual ~ITestCase(); }; class TestCase; struct IConfig; struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); } namespace Catch { template class MethodTestCase : public SharedImpl { public: MethodTestCase( void (C::*method)() ) : m_method( method ) {} virtual void invoke() const { C obj; (obj.*m_method)(); } private: virtual ~MethodTestCase() {} void (C::*m_method)(); }; typedef void(*TestFunction)(); struct NameAndDesc { NameAndDesc( const char* _name = "", const char* _description= "" ) : name( _name ), description( _description ) {} const char* name; const char* description; }; void registerTestCase ( ITestCase* testCase, char const* className, NameAndDesc const& nameAndDesc, SourceLineInfo const& lineInfo ); struct AutoReg { AutoReg ( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ); template AutoReg ( void (C::*method)(), char const* className, NameAndDesc const& nameAndDesc, SourceLineInfo const& lineInfo ) { registerTestCase ( new MethodTestCase( method ), className, nameAndDesc, lineInfo ); } ~AutoReg(); private: AutoReg( AutoReg const& ); void operator= ( AutoReg const& ); }; void registerTestCaseFunction ( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ); } // end namespace Catch #ifdef CATCH_CONFIG_VARIADIC_MACROS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ \ struct TestName : ClassName{ \ void test(); \ }; \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \ } \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS #else /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \ static void TestName(); \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ \ struct TestCaseName : ClassName{ \ void test(); \ }; \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \ } \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ void TestCaseName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS #endif // #included from: internal/catch_capture.hpp #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED // #included from: catch_result_builder.h #define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED // #included from: catch_result_type.h #define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED namespace Catch { // ResultWas::OfType enum struct ResultWas { enum OfType { Unknown = -1, Ok = 0, Info = 1, Warning = 2, FailureBit = 0x10, ExpressionFailed = FailureBit | 1, ExplicitFailure = FailureBit | 2, Exception = 0x100 | FailureBit, ThrewException = Exception | 1, DidntThrowException = Exception | 2, FatalErrorCondition = 0x200 | FailureBit }; }; inline bool isOk( ResultWas::OfType resultType ) { return ( resultType & ResultWas::FailureBit ) == 0; } inline bool isJustInfo( int flags ) { return flags == ResultWas::Info; } // ResultDisposition::Flags enum struct ResultDisposition { enum Flags { Normal = 0x01, ContinueOnFailure = 0x02, // Failures fail test, but execution continues FalseTest = 0x04, // Prefix expression with ! SuppressFail = 0x08 // Failures are reported but do not fail the test }; }; inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { return static_cast( static_cast( lhs ) | static_cast( rhs ) ); } inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } } // end namespace Catch // #included from: catch_assertionresult.h #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED #include namespace Catch { struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; struct DecomposedExpression { virtual ~DecomposedExpression() {} virtual bool isBinaryExpression() const { return false; } virtual void reconstructExpression( std::string& dest ) const = 0; // Only simple binary comparisons can be decomposed. // If more complex check is required then wrap sub-expressions in parentheses. template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& ); private: DecomposedExpression& operator = (DecomposedExpression const&); }; struct AssertionInfo { AssertionInfo(); AssertionInfo( char const * _macroName, SourceLineInfo const& _lineInfo, char const * _capturedExpression, ResultDisposition::Flags _resultDisposition, char const * _secondArg = ""); char const * macroName; SourceLineInfo lineInfo; char const * capturedExpression; ResultDisposition::Flags resultDisposition; char const * secondArg; }; struct AssertionResultData { AssertionResultData() : decomposedExpression( CATCH_NULL ) , resultType( ResultWas::Unknown ) , negated( false ) , parenthesized( false ) {} void negate( bool parenthesize ) { negated = !negated; parenthesized = parenthesize; if( resultType == ResultWas::Ok ) resultType = ResultWas::ExpressionFailed; else if( resultType == ResultWas::ExpressionFailed ) resultType = ResultWas::Ok; } std::string const& reconstructExpression() const { if( decomposedExpression != CATCH_NULL ) { decomposedExpression->reconstructExpression( reconstructedExpression ); if( parenthesized ) { reconstructedExpression.insert( 0, 1, '(' ); reconstructedExpression.append( 1, ')' ); } if( negated ) { reconstructedExpression.insert( 0, 1, '!' ); } decomposedExpression = CATCH_NULL; } return reconstructedExpression; } mutable DecomposedExpression const* decomposedExpression; mutable std::string reconstructedExpression; std::string message; ResultWas::OfType resultType; bool negated; bool parenthesized; }; class AssertionResult { public: AssertionResult(); AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); ~AssertionResult(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS AssertionResult( AssertionResult const& ) = default; AssertionResult( AssertionResult && ) = default; AssertionResult& operator = ( AssertionResult const& ) = default; AssertionResult& operator = ( AssertionResult && ) = default; # endif bool isOk() const; bool succeeded() const; ResultWas::OfType getResultType() const; bool hasExpression() const; bool hasMessage() const; std::string getExpression() const; std::string getExpressionInMacro() const; bool hasExpandedExpression() const; std::string getExpandedExpression() const; std::string getMessage() const; SourceLineInfo getSourceInfo() const; std::string getTestMacroName() const; void discardDecomposedExpression() const; void expandDecomposedExpression() const; protected: AssertionInfo m_info; AssertionResultData m_resultData; }; } // end namespace Catch // #included from: catch_matchers.hpp #define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED namespace Catch { namespace Matchers { namespace Impl { template struct MatchAllOf; template struct MatchAnyOf; template struct MatchNotOf; class MatcherUntypedBase { public: std::string toString() const { if( m_cachedToString.empty() ) m_cachedToString = describe(); return m_cachedToString; } protected: virtual ~MatcherUntypedBase(); virtual std::string describe() const = 0; mutable std::string m_cachedToString; private: MatcherUntypedBase& operator = ( MatcherUntypedBase const& ); }; template struct MatcherMethod { virtual bool match( ObjectT const& arg ) const = 0; }; template struct MatcherMethod { virtual bool match( PtrT* arg ) const = 0; }; template struct MatcherBase : MatcherUntypedBase, MatcherMethod { MatchAllOf operator && ( MatcherBase const& other ) const; MatchAnyOf operator || ( MatcherBase const& other ) const; MatchNotOf operator ! () const; }; template struct MatchAllOf : MatcherBase { virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if (!m_matchers[i]->match(arg)) return false; } return true; } virtual std::string describe() const CATCH_OVERRIDE { std::string description; description.reserve( 4 + m_matchers.size()*32 ); description += "( "; for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if( i != 0 ) description += " and "; description += m_matchers[i]->toString(); } description += " )"; return description; } MatchAllOf& operator && ( MatcherBase const& other ) { m_matchers.push_back( &other ); return *this; } std::vector const*> m_matchers; }; template struct MatchAnyOf : MatcherBase { virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if (m_matchers[i]->match(arg)) return true; } return false; } virtual std::string describe() const CATCH_OVERRIDE { std::string description; description.reserve( 4 + m_matchers.size()*32 ); description += "( "; for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if( i != 0 ) description += " or "; description += m_matchers[i]->toString(); } description += " )"; return description; } MatchAnyOf& operator || ( MatcherBase const& other ) { m_matchers.push_back( &other ); return *this; } std::vector const*> m_matchers; }; template struct MatchNotOf : MatcherBase { MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { return !m_underlyingMatcher.match( arg ); } virtual std::string describe() const CATCH_OVERRIDE { return "not " + m_underlyingMatcher.toString(); } MatcherBase const& m_underlyingMatcher; }; template MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { return MatchAllOf() && *this && other; } template MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { return MatchAnyOf() || *this || other; } template MatchNotOf MatcherBase::operator ! () const { return MatchNotOf( *this ); } } // namespace Impl // The following functions create the actual matcher objects. // This allows the types to be inferred // - deprecated: prefer ||, && and ! template Impl::MatchNotOf Not( Impl::MatcherBase const& underlyingMatcher ) { return Impl::MatchNotOf( underlyingMatcher ); } template Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { return Impl::MatchAllOf() && m1 && m2; } template Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { return Impl::MatchAllOf() && m1 && m2 && m3; } template Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { return Impl::MatchAnyOf() || m1 || m2; } template Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { return Impl::MatchAnyOf() || m1 || m2 || m3; } } // namespace Matchers using namespace Matchers; using Matchers::Impl::MatcherBase; } // namespace Catch namespace Catch { struct TestFailureException{}; template class ExpressionLhs; struct CopyableStream { CopyableStream() {} CopyableStream( CopyableStream const& other ) { oss << other.oss.str(); } CopyableStream& operator=( CopyableStream const& other ) { oss.str(std::string()); oss << other.oss.str(); return *this; } std::ostringstream oss; }; class ResultBuilder : public DecomposedExpression { public: ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, ResultDisposition::Flags resultDisposition, char const* secondArg = "" ); ~ResultBuilder(); template ExpressionLhs operator <= ( T const& operand ); ExpressionLhs operator <= ( bool value ); template ResultBuilder& operator << ( T const& value ) { stream().oss << value; return *this; } ResultBuilder& setResultType( ResultWas::OfType result ); ResultBuilder& setResultType( bool result ); void endExpression( DecomposedExpression const& expr ); virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE; AssertionResult build() const; AssertionResult build( DecomposedExpression const& expr ) const; void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); void captureResult( ResultWas::OfType resultType ); void captureExpression(); void captureExpectedException( std::string const& expectedMessage ); void captureExpectedException( Matchers::Impl::MatcherBase const& matcher ); void handleResult( AssertionResult const& result ); void react(); bool shouldDebugBreak() const; bool allowThrows() const; template void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ); void setExceptionGuard(); void unsetExceptionGuard(); private: AssertionInfo m_assertionInfo; AssertionResultData m_data; CopyableStream &stream() { if(!m_usedStream) { m_usedStream = true; m_stream().oss.str(""); } return m_stream(); } static CopyableStream &m_stream() { static CopyableStream s; return s; } bool m_shouldDebugBreak; bool m_shouldThrow; bool m_guardException; bool m_usedStream; }; } // namespace Catch // Include after due to circular dependency: // #included from: catch_expression_lhs.hpp #define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED // #included from: catch_evaluate.hpp #define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4389) // '==' : signed/unsigned mismatch #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) #endif #include namespace Catch { namespace Internal { enum Operator { IsEqualTo, IsNotEqualTo, IsLessThan, IsGreaterThan, IsLessThanOrEqualTo, IsGreaterThanOrEqualTo }; template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; template T& opCast(T const& t) { return const_cast(t); } // nullptr_t support based on pull request #154 from Konstantin Baumann #ifdef CATCH_CONFIG_CPP11_NULLPTR inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } #endif // CATCH_CONFIG_CPP11_NULLPTR // So the compare overloads can be operator agnostic we convey the operator as a template // enum, which is used to specialise an Evaluator for doing the comparison. template struct Evaluator{}; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs) { return bool( opCast( lhs ) == opCast( rhs ) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return bool( opCast( lhs ) != opCast( rhs ) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return bool( opCast( lhs ) < opCast( rhs ) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return bool( opCast( lhs ) > opCast( rhs ) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return bool( opCast( lhs ) >= opCast( rhs ) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return bool( opCast( lhs ) <= opCast( rhs ) ); } }; template bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { return Evaluator::evaluate( lhs, rhs ); } // This level of indirection allows us to specialise for integer types // to avoid signed/ unsigned warnings // "base" overload template bool compare( T1 const& lhs, T2 const& rhs ) { return Evaluator::evaluate( lhs, rhs ); } // unsigned X to int template bool compare( unsigned int lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned long lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned char lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } // unsigned X to long template bool compare( unsigned int lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned long lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned char lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } // int to unsigned X template bool compare( int lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( int lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( int lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // long to unsigned X template bool compare( long lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // pointer to long (when comparing against NULL) template bool compare( long lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( T* lhs, long rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } // pointer to int (when comparing against NULL) template bool compare( int lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( T* lhs, int rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } #ifdef CATCH_CONFIG_CPP11_LONG_LONG // long long to unsigned X template bool compare( long long lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long long lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long long lhs, unsigned long long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long long lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // unsigned long long to X template bool compare( unsigned long long lhs, int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( unsigned long long lhs, long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( unsigned long long lhs, long long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( unsigned long long lhs, char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // pointer to long long (when comparing against NULL) template bool compare( long long lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( T* lhs, long long rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } #endif // CATCH_CONFIG_CPP11_LONG_LONG #ifdef CATCH_CONFIG_CPP11_NULLPTR // pointer to nullptr_t (when comparing against nullptr) template bool compare( std::nullptr_t, T* rhs ) { return Evaluator::evaluate( nullptr, rhs ); } template bool compare( T* lhs, std::nullptr_t ) { return Evaluator::evaluate( lhs, nullptr ); } #endif // CATCH_CONFIG_CPP11_NULLPTR } // end of namespace Internal } // end of namespace Catch #ifdef _MSC_VER #pragma warning(pop) #endif // #included from: catch_tostring.h #define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED #include #include #include #include #include #ifdef __OBJC__ // #included from: catch_objc_arc.hpp #define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED #import #ifdef __has_feature #define CATCH_ARC_ENABLED __has_feature(objc_arc) #else #define CATCH_ARC_ENABLED 0 #endif void arcSafeRelease( NSObject* obj ); id performOptionalSelector( id obj, SEL sel ); #if !CATCH_ARC_ENABLED inline void arcSafeRelease( NSObject* obj ) { [obj release]; } inline id performOptionalSelector( id obj, SEL sel ) { if( [obj respondsToSelector: sel] ) return [obj performSelector: sel]; return nil; } #define CATCH_UNSAFE_UNRETAINED #define CATCH_ARC_STRONG #else inline void arcSafeRelease( NSObject* ){} inline id performOptionalSelector( id obj, SEL sel ) { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" #endif if( [obj respondsToSelector: sel] ) return [obj performSelector: sel]; #ifdef __clang__ #pragma clang diagnostic pop #endif return nil; } #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained #define CATCH_ARC_STRONG __strong #endif #endif #ifdef CATCH_CONFIG_CPP11_TUPLE #include #endif #ifdef CATCH_CONFIG_CPP11_IS_ENUM #include #endif namespace Catch { // Why we're here. template std::string toString( T const& value ); // Built in overloads std::string toString( std::string const& value ); std::string toString( std::wstring const& value ); std::string toString( const char* const value ); std::string toString( char* const value ); std::string toString( const wchar_t* const value ); std::string toString( wchar_t* const value ); std::string toString( int value ); std::string toString( unsigned long value ); std::string toString( unsigned int value ); std::string toString( const double value ); std::string toString( const float value ); std::string toString( bool value ); std::string toString( char value ); std::string toString( signed char value ); std::string toString( unsigned char value ); #ifdef CATCH_CONFIG_CPP11_LONG_LONG std::string toString( long long value ); std::string toString( unsigned long long value ); #endif #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ); #endif #ifdef __OBJC__ std::string toString( NSString const * const& nsstring ); std::string toString( NSString * CATCH_ARC_STRONG & nsstring ); std::string toString( NSObject* const& nsObject ); #endif namespace Detail { extern const std::string unprintableString; #if !defined(CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK) struct BorgType { template BorgType( T const& ); }; struct TrueType { char sizer[1]; }; struct FalseType { char sizer[2]; }; TrueType& testStreamable( std::ostream& ); FalseType testStreamable( FalseType ); FalseType operator<<( std::ostream const&, BorgType const& ); template struct IsStreamInsertable { static std::ostream &s; static T const&t; enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; }; #else template class IsStreamInsertable { template static auto test(int) -> decltype( std::declval() << std::declval(), std::true_type() ); template static auto test(...) -> std::false_type; public: static const bool value = decltype(test(0))::value; }; #endif #if defined(CATCH_CONFIG_CPP11_IS_ENUM) template::value > struct EnumStringMaker { static std::string convert( T const& ) { return unprintableString; } }; template struct EnumStringMaker { static std::string convert( T const& v ) { return ::Catch::toString( static_cast::type>(v) ); } }; #endif template struct StringMakerBase { #if defined(CATCH_CONFIG_CPP11_IS_ENUM) template static std::string convert( T const& v ) { return EnumStringMaker::convert( v ); } #else template static std::string convert( T const& ) { return unprintableString; } #endif }; template<> struct StringMakerBase { template static std::string convert( T const& _value ) { std::ostringstream oss; oss << _value; return oss.str(); } }; std::string rawMemoryToString( const void *object, std::size_t size ); template std::string rawMemoryToString( const T& object ) { return rawMemoryToString( &object, sizeof(object) ); } } // end namespace Detail template struct StringMaker : Detail::StringMakerBase::value> {}; template struct StringMaker { template static std::string convert( U* p ) { if( !p ) return "NULL"; else return Detail::rawMemoryToString( p ); } }; template struct StringMaker { static std::string convert( R C::* p ) { if( !p ) return "NULL"; else return Detail::rawMemoryToString( p ); } }; namespace Detail { template std::string rangeToString( InputIterator first, InputIterator last ); } //template //struct StringMaker > { // static std::string convert( std::vector const& v ) { // return Detail::rangeToString( v.begin(), v.end() ); // } //}; template std::string toString( std::vector const& v ) { return Detail::rangeToString( v.begin(), v.end() ); } #ifdef CATCH_CONFIG_CPP11_TUPLE // toString for tuples namespace TupleDetail { template< typename Tuple, std::size_t N = 0, bool = (N < std::tuple_size::value) > struct ElementPrinter { static void print( const Tuple& tuple, std::ostream& os ) { os << ( N ? ", " : " " ) << Catch::toString(std::get(tuple)); ElementPrinter::print(tuple,os); } }; template< typename Tuple, std::size_t N > struct ElementPrinter { static void print( const Tuple&, std::ostream& ) {} }; } template struct StringMaker> { static std::string convert( const std::tuple& tuple ) { std::ostringstream os; os << '{'; TupleDetail::ElementPrinter>::print( tuple, os ); os << " }"; return os.str(); } }; #endif // CATCH_CONFIG_CPP11_TUPLE namespace Detail { template std::string makeString( T const& value ) { return StringMaker::convert( value ); } } // end namespace Detail /// \brief converts any type to a string /// /// The default template forwards on to ostringstream - except when an /// ostringstream overload does not exist - in which case it attempts to detect /// that and writes {?}. /// Overload (not specialise) this template for custom typs that you don't want /// to provide an ostream overload for. template std::string toString( T const& value ) { return StringMaker::convert( value ); } namespace Detail { template std::string rangeToString( InputIterator first, InputIterator last ) { std::ostringstream oss; oss << "{ "; if( first != last ) { oss << Catch::toString( *first ); for( ++first ; first != last ; ++first ) oss << ", " << Catch::toString( *first ); } oss << " }"; return oss.str(); } } } // end namespace Catch namespace Catch { template class BinaryExpression; template class MatchExpression; // Wraps the LHS of an expression and overloads comparison operators // for also capturing those and RHS (if any) template class ExpressionLhs : public DecomposedExpression { public: ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {} ExpressionLhs& operator = ( const ExpressionLhs& ); template BinaryExpression operator == ( RhsT const& rhs ) { return captureExpression( rhs ); } template BinaryExpression operator != ( RhsT const& rhs ) { return captureExpression( rhs ); } template BinaryExpression operator < ( RhsT const& rhs ) { return captureExpression( rhs ); } template BinaryExpression operator > ( RhsT const& rhs ) { return captureExpression( rhs ); } template BinaryExpression operator <= ( RhsT const& rhs ) { return captureExpression( rhs ); } template BinaryExpression operator >= ( RhsT const& rhs ) { return captureExpression( rhs ); } BinaryExpression operator == ( bool rhs ) { return captureExpression( rhs ); } BinaryExpression operator != ( bool rhs ) { return captureExpression( rhs ); } void endExpression() { m_truthy = m_lhs ? true : false; m_rb .setResultType( m_truthy ) .endExpression( *this ); } virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { dest = Catch::toString( m_lhs ); } private: template BinaryExpression captureExpression( RhsT& rhs ) const { return BinaryExpression( m_rb, m_lhs, rhs ); } template BinaryExpression captureExpression( bool rhs ) const { return BinaryExpression( m_rb, m_lhs, rhs ); } private: ResultBuilder& m_rb; T m_lhs; bool m_truthy; }; template class BinaryExpression : public DecomposedExpression { public: BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs ) : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {} BinaryExpression& operator = ( BinaryExpression& ); void endExpression() const { m_rb .setResultType( Internal::compare( m_lhs, m_rhs ) ) .endExpression( *this ); } virtual bool isBinaryExpression() const CATCH_OVERRIDE { return true; } virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { std::string lhs = Catch::toString( m_lhs ); std::string rhs = Catch::toString( m_rhs ); char delim = lhs.size() + rhs.size() < 40 && lhs.find('\n') == std::string::npos && rhs.find('\n') == std::string::npos ? ' ' : '\n'; dest.reserve( 7 + lhs.size() + rhs.size() ); // 2 for spaces around operator // 2 for operator // 2 for parentheses (conditionally added later) // 1 for negation (conditionally added later) dest = lhs; dest += delim; dest += Internal::OperatorTraits::getName(); dest += delim; dest += rhs; } private: ResultBuilder& m_rb; LhsT m_lhs; RhsT m_rhs; }; template class MatchExpression : public DecomposedExpression { public: MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString ) : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {} virtual bool isBinaryExpression() const CATCH_OVERRIDE { return true; } virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { std::string matcherAsString = m_matcher.toString(); dest = Catch::toString( m_arg ); dest += ' '; if( matcherAsString == Detail::unprintableString ) dest += m_matcherString; else dest += matcherAsString; } private: ArgT m_arg; MatcherT m_matcher; char const* m_matcherString; }; } // end namespace Catch namespace Catch { template ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { return ExpressionLhs( *this, operand ); } inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { return ExpressionLhs( *this, value ); } template void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ) { MatchExpression expr( arg, matcher, matcherString ); setResultType( matcher.match( arg ) ); endExpression( expr ); } } // namespace Catch // #included from: catch_message.h #define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED #include namespace Catch { struct MessageInfo { MessageInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ); std::string macroName; SourceLineInfo lineInfo; ResultWas::OfType type; std::string message; unsigned int sequence; bool operator == ( MessageInfo const& other ) const { return sequence == other.sequence; } bool operator < ( MessageInfo const& other ) const { return sequence < other.sequence; } private: static unsigned int globalCount; }; struct MessageBuilder { MessageBuilder( std::string const& macroName, SourceLineInfo const& lineInfo, ResultWas::OfType type ) : m_info( macroName, lineInfo, type ) {} template MessageBuilder& operator << ( T const& value ) { m_stream << value; return *this; } MessageInfo m_info; std::ostringstream m_stream; }; class ScopedMessage { public: ScopedMessage( MessageBuilder const& builder ); ScopedMessage( ScopedMessage const& other ); ~ScopedMessage(); MessageInfo m_info; }; } // end namespace Catch // #included from: catch_interfaces_capture.h #define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED #include namespace Catch { class TestCase; class AssertionResult; struct AssertionInfo; struct SectionInfo; struct SectionEndInfo; struct MessageInfo; class ScopedMessageBuilder; struct Counts; struct IResultCapture { virtual ~IResultCapture(); virtual void assertionEnded( AssertionResult const& result ) = 0; virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 0; virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; virtual std::string getCurrentTestName() const = 0; virtual const AssertionResult* getLastResult() const = 0; virtual void exceptionEarlyReported() = 0; virtual void handleFatalErrorCondition( std::string const& message ) = 0; virtual bool lastAssertionPassed() = 0; virtual void assertionPassed() = 0; virtual void assertionRun() = 0; }; IResultCapture& getResultCapture(); } // #included from: catch_debugger.h #define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED // #included from: catch_platform.h #define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) # define CATCH_PLATFORM_MAC #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) # define CATCH_PLATFORM_IPHONE #elif defined(linux) || defined(__linux) || defined(__linux__) # define CATCH_PLATFORM_LINUX #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) # define CATCH_PLATFORM_WINDOWS # if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) # define CATCH_DEFINES_NOMINMAX # endif # if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) # define CATCH_DEFINES_WIN32_LEAN_AND_MEAN # endif #endif #include namespace Catch{ bool isDebuggerActive(); void writeToDebugConsole( std::string const& text ); } #ifdef CATCH_PLATFORM_MAC // The following code snippet based on: // http://cocoawithlove.com/2008/03/break-into-debugger.html #if defined(__ppc64__) || defined(__ppc__) #define CATCH_TRAP() \ __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ : : : "memory","r0","r3","r4" ) /* NOLINT */ #else #define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ ) #endif #elif defined(CATCH_PLATFORM_LINUX) // If we can use inline assembler, do it because this allows us to break // directly at the location of the failing check instead of breaking inside // raise() called from it, i.e. one stack frame below. #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ #else // Fall back to the generic way. #include #define CATCH_TRAP() raise(SIGTRAP) #endif #elif defined(_MSC_VER) #define CATCH_TRAP() __debugbreak() #elif defined(__MINGW32__) extern "C" __declspec(dllimport) void __stdcall DebugBreak(); #define CATCH_TRAP() DebugBreak() #endif #ifdef CATCH_TRAP #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } #else #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); #endif // #included from: catch_interfaces_runner.h #define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED namespace Catch { class TestCase; struct IRunner { virtual ~IRunner(); virtual bool aborting() const = 0; }; } #if defined(CATCH_CONFIG_FAST_COMPILE) /////////////////////////////////////////////////////////////////////////////// // We can speedup compilation significantly by breaking into debugger lower in // the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER // macro in each assertion #define INTERNAL_CATCH_REACT( resultBuilder ) \ resultBuilder.react(); /////////////////////////////////////////////////////////////////////////////// // Another way to speed-up compilation is to omit local try-catch for REQUIRE* // macros. // This can potentially cause false negative, if the test code catches // the exception before it propagates back up to the runner. #define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ __catchResult.setExceptionGuard(); \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ ( __catchResult <= expr ).endExpression(); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ __catchResult.unsetExceptionGuard(); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::isTrue( false && static_cast( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. #define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ __catchResult.setExceptionGuard(); \ __catchResult.captureMatch( arg, matcher, #matcher ); \ __catchResult.unsetExceptionGuard(); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) #else /////////////////////////////////////////////////////////////////////////////// // In the event of a failure works out if the debugger needs to be invoked // and/or an exception thrown and takes appropriate action. // This needs to be done as a macro so the debugger will stop in the user // source code rather than in Catch library code #define INTERNAL_CATCH_REACT( resultBuilder ) \ if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ resultBuilder.react(); #endif /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ try { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ ( __catchResult <= expr ).endExpression(); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ } \ catch( ... ) { \ __catchResult.useActiveException( resultDisposition ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::isTrue( false && static_cast( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \ INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ if( Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \ INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ if( !Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ try { \ static_cast(expr); \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ __catchResult.useActiveException( resultDisposition ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ if( __catchResult.allowThrows() ) \ try { \ static_cast(expr); \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ __catchResult.captureExpectedException( matcher ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \ if( __catchResult.allowThrows() ) \ try { \ static_cast(expr); \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( exceptionType ) { \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ __catchResult.useActiveException( resultDisposition ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #ifdef CATCH_CONFIG_VARIADIC_MACROS #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ __catchResult.captureResult( messageType ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) #else #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ __catchResult << log + ::Catch::StreamEndStop(); \ __catchResult.captureResult( messageType ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) #endif /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_INFO( macroName, log ) \ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ try { \ __catchResult.captureMatch( arg, matcher, #matcher ); \ } catch( ... ) { \ __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) // #included from: internal/catch_section.h #define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED // #included from: catch_section_info.h #define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED // #included from: catch_totals.hpp #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED #include namespace Catch { struct Counts { Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} Counts operator - ( Counts const& other ) const { Counts diff; diff.passed = passed - other.passed; diff.failed = failed - other.failed; diff.failedButOk = failedButOk - other.failedButOk; return diff; } Counts& operator += ( Counts const& other ) { passed += other.passed; failed += other.failed; failedButOk += other.failedButOk; return *this; } std::size_t total() const { return passed + failed + failedButOk; } bool allPassed() const { return failed == 0 && failedButOk == 0; } bool allOk() const { return failed == 0; } std::size_t passed; std::size_t failed; std::size_t failedButOk; }; struct Totals { Totals operator - ( Totals const& other ) const { Totals diff; diff.assertions = assertions - other.assertions; diff.testCases = testCases - other.testCases; return diff; } Totals delta( Totals const& prevTotals ) const { Totals diff = *this - prevTotals; if( diff.assertions.failed > 0 ) ++diff.testCases.failed; else if( diff.assertions.failedButOk > 0 ) ++diff.testCases.failedButOk; else ++diff.testCases.passed; return diff; } Totals& operator += ( Totals const& other ) { assertions += other.assertions; testCases += other.testCases; return *this; } Counts assertions; Counts testCases; }; } #include namespace Catch { struct SectionInfo { SectionInfo ( SourceLineInfo const& _lineInfo, std::string const& _name, std::string const& _description = std::string() ); std::string name; std::string description; SourceLineInfo lineInfo; }; struct SectionEndInfo { SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) {} SectionInfo sectionInfo; Counts prevAssertions; double durationInSeconds; }; } // end namespace Catch // #included from: catch_timer.h #define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED #ifdef _MSC_VER namespace Catch { typedef unsigned long long UInt64; } #else #include namespace Catch { typedef uint64_t UInt64; } #endif namespace Catch { class Timer { public: Timer() : m_ticks( 0 ) {} void start(); unsigned int getElapsedMicroseconds() const; unsigned int getElapsedMilliseconds() const; double getElapsedSeconds() const; private: UInt64 m_ticks; }; } // namespace Catch #include namespace Catch { class Section : NonCopyable { public: Section( SectionInfo const& info ); ~Section(); // This indicates whether the section should be executed or not operator bool() const; private: SectionInfo m_info; std::string m_name; Counts m_assertions; bool m_sectionIncluded; Timer m_timer; }; } // end namespace Catch #ifdef CATCH_CONFIG_VARIADIC_MACROS #define INTERNAL_CATCH_SECTION( ... ) \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) #else #define INTERNAL_CATCH_SECTION( name, desc ) \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) #endif // #included from: internal/catch_generators.hpp #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED #include #include #include namespace Catch { template struct IGenerator { virtual ~IGenerator() {} virtual T getValue( std::size_t index ) const = 0; virtual std::size_t size () const = 0; }; template class BetweenGenerator : public IGenerator { public: BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} virtual T getValue( std::size_t index ) const { return m_from+static_cast( index ); } virtual std::size_t size() const { return static_cast( 1+m_to-m_from ); } private: T m_from; T m_to; }; template class ValuesGenerator : public IGenerator { public: ValuesGenerator(){} void add( T value ) { m_values.push_back( value ); } virtual T getValue( std::size_t index ) const { return m_values[index]; } virtual std::size_t size() const { return m_values.size(); } private: std::vector m_values; }; template class CompositeGenerator { public: CompositeGenerator() : m_totalSize( 0 ) {} // *** Move semantics, similar to auto_ptr *** CompositeGenerator( CompositeGenerator& other ) : m_fileInfo( other.m_fileInfo ), m_totalSize( 0 ) { move( other ); } CompositeGenerator& setFileInfo( const char* fileInfo ) { m_fileInfo = fileInfo; return *this; } ~CompositeGenerator() { deleteAll( m_composed ); } operator T () const { size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); typename std::vector*>::const_iterator it = m_composed.begin(); typename std::vector*>::const_iterator itEnd = m_composed.end(); for( size_t index = 0; it != itEnd; ++it ) { const IGenerator* generator = *it; if( overallIndex >= index && overallIndex < index + generator->size() ) { return generator->getValue( overallIndex-index ); } index += generator->size(); } CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so } void add( const IGenerator* generator ) { m_totalSize += generator->size(); m_composed.push_back( generator ); } CompositeGenerator& then( CompositeGenerator& other ) { move( other ); return *this; } CompositeGenerator& then( T value ) { ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( value ); add( valuesGen ); return *this; } private: void move( CompositeGenerator& other ) { m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() ); m_totalSize += other.m_totalSize; other.m_composed.clear(); } std::vector*> m_composed; std::string m_fileInfo; size_t m_totalSize; }; namespace Generators { template CompositeGenerator between( T from, T to ) { CompositeGenerator generators; generators.add( new BetweenGenerator( from, to ) ); return generators; } template CompositeGenerator values( T val1, T val2 ) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); generators.add( valuesGen ); return generators; } template CompositeGenerator values( T val1, T val2, T val3 ){ CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); valuesGen->add( val3 ); generators.add( valuesGen ); return generators; } template CompositeGenerator values( T val1, T val2, T val3, T val4 ) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); valuesGen->add( val3 ); valuesGen->add( val4 ); generators.add( valuesGen ); return generators; } } // end namespace Generators using namespace Generators; } // end namespace Catch #define INTERNAL_CATCH_LINESTR2( line ) #line #define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) #define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) // #included from: internal/catch_interfaces_exception.h #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED #include #include // #included from: catch_interfaces_registry_hub.h #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED #include namespace Catch { class TestCase; struct ITestCaseRegistry; struct IExceptionTranslatorRegistry; struct IExceptionTranslator; struct IReporterRegistry; struct IReporterFactory; struct ITagAliasRegistry; struct IRegistryHub { virtual ~IRegistryHub(); virtual IReporterRegistry const& getReporterRegistry() const = 0; virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; }; struct IMutableRegistryHub { virtual ~IMutableRegistryHub(); virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; virtual void registerListener( Ptr const& factory ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; }; IRegistryHub& getRegistryHub(); IMutableRegistryHub& getMutableRegistryHub(); void cleanUp(); std::string translateActiveException(); } namespace Catch { typedef std::string(*exceptionTranslateFunction)(); struct IExceptionTranslator; typedef std::vector ExceptionTranslators; struct IExceptionTranslator { virtual ~IExceptionTranslator(); virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; }; struct IExceptionTranslatorRegistry { virtual ~IExceptionTranslatorRegistry(); virtual std::string translateActiveException() const = 0; }; class ExceptionTranslatorRegistrar { template class ExceptionTranslator : public IExceptionTranslator { public: ExceptionTranslator( std::string(*translateFunction)( T& ) ) : m_translateFunction( translateFunction ) {} virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { try { if( it == itEnd ) throw; else return (*it)->translate( it+1, itEnd ); } catch( T& ex ) { return m_translateFunction( ex ); } } protected: std::string(*m_translateFunction)( T& ); }; public: template ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { getMutableRegistryHub().registerTranslator ( new ExceptionTranslator( translateFunction ) ); } }; } /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ static std::string translatorName( signature ); \ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\ static std::string translatorName( signature ) #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) // #included from: internal/catch_approx.hpp #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED #include #include #if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) #include #endif namespace Catch { namespace Detail { class Approx { public: explicit Approx ( double value ) : m_epsilon( std::numeric_limits::epsilon()*100 ), m_margin( 0.0 ), m_scale( 1.0 ), m_value( value ) {} static Approx custom() { return Approx( 0 ); } #if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) template ::value>::type> Approx operator()( T value ) { Approx approx( static_cast(value) ); approx.epsilon( m_epsilon ); approx.margin( m_margin ); approx.scale( m_scale ); return approx; } template ::value>::type> explicit Approx( T value ): Approx(static_cast(value)) {} template ::value>::type> friend bool operator == ( const T& lhs, Approx const& rhs ) { // Thanks to Richard Harris for his help refining this formula auto lhs_v = double(lhs); bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value))); if (relativeOK) { return true; } return std::fabs(lhs_v - rhs.m_value) < rhs.m_margin; } template ::value>::type> friend bool operator == ( Approx const& lhs, const T& rhs ) { return operator==( rhs, lhs ); } template ::value>::type> friend bool operator != ( T lhs, Approx const& rhs ) { return !operator==( lhs, rhs ); } template ::value>::type> friend bool operator != ( Approx const& lhs, T rhs ) { return !operator==( rhs, lhs ); } template ::value>::type> friend bool operator <= ( T lhs, Approx const& rhs ) { return double(lhs) < rhs.m_value || lhs == rhs; } template ::value>::type> friend bool operator <= ( Approx const& lhs, T rhs ) { return lhs.m_value < double(rhs) || lhs == rhs; } template ::value>::type> friend bool operator >= ( T lhs, Approx const& rhs ) { return double(lhs) > rhs.m_value || lhs == rhs; } template ::value>::type> friend bool operator >= ( Approx const& lhs, T rhs ) { return lhs.m_value > double(rhs) || lhs == rhs; } template ::value>::type> Approx& epsilon( T newEpsilon ) { m_epsilon = double(newEpsilon); return *this; } template ::value>::type> Approx& margin( T newMargin ) { m_margin = double(newMargin); return *this; } template ::value>::type> Approx& scale( T newScale ) { m_scale = double(newScale); return *this; } #else Approx operator()( double value ) { Approx approx( value ); approx.epsilon( m_epsilon ); approx.margin( m_margin ); approx.scale( m_scale ); return approx; } friend bool operator == ( double lhs, Approx const& rhs ) { // Thanks to Richard Harris for his help refining this formula bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) ); if (relativeOK) { return true; } return std::fabs(lhs - rhs.m_value) < rhs.m_margin; } friend bool operator == ( Approx const& lhs, double rhs ) { return operator==( rhs, lhs ); } friend bool operator != ( double lhs, Approx const& rhs ) { return !operator==( lhs, rhs ); } friend bool operator != ( Approx const& lhs, double rhs ) { return !operator==( rhs, lhs ); } friend bool operator <= ( double lhs, Approx const& rhs ) { return lhs < rhs.m_value || lhs == rhs; } friend bool operator <= ( Approx const& lhs, double rhs ) { return lhs.m_value < rhs || lhs == rhs; } friend bool operator >= ( double lhs, Approx const& rhs ) { return lhs > rhs.m_value || lhs == rhs; } friend bool operator >= ( Approx const& lhs, double rhs ) { return lhs.m_value > rhs || lhs == rhs; } Approx& epsilon( double newEpsilon ) { m_epsilon = newEpsilon; return *this; } Approx& margin( double newMargin ) { m_margin = newMargin; return *this; } Approx& scale( double newScale ) { m_scale = newScale; return *this; } #endif std::string toString() const { std::ostringstream oss; oss << "Approx( " << Catch::toString( m_value ) << " )"; return oss.str(); } private: double m_epsilon; double m_margin; double m_scale; double m_value; }; } template<> inline std::string toString( Detail::Approx const& value ) { return value.toString(); } } // end namespace Catch // #included from: internal/catch_matchers_string.h #define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED namespace Catch { namespace Matchers { namespace StdString { struct CasedString { CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); std::string adjustString( std::string const& str ) const; std::string caseSensitivitySuffix() const; CaseSensitive::Choice m_caseSensitivity; std::string m_str; }; struct StringMatcherBase : MatcherBase { StringMatcherBase( std::string const& operation, CasedString const& comparator ); virtual std::string describe() const CATCH_OVERRIDE; CasedString m_comparator; std::string m_operation; }; struct EqualsMatcher : StringMatcherBase { EqualsMatcher( CasedString const& comparator ); virtual bool match( std::string const& source ) const CATCH_OVERRIDE; }; struct ContainsMatcher : StringMatcherBase { ContainsMatcher( CasedString const& comparator ); virtual bool match( std::string const& source ) const CATCH_OVERRIDE; }; struct StartsWithMatcher : StringMatcherBase { StartsWithMatcher( CasedString const& comparator ); virtual bool match( std::string const& source ) const CATCH_OVERRIDE; }; struct EndsWithMatcher : StringMatcherBase { EndsWithMatcher( CasedString const& comparator ); virtual bool match( std::string const& source ) const CATCH_OVERRIDE; }; } // namespace StdString // The following functions create the actual matcher objects. // This allows the types to be inferred StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); } // namespace Matchers } // namespace Catch // #included from: internal/catch_matchers_vector.h #define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED namespace Catch { namespace Matchers { namespace Vector { template struct ContainsElementMatcher : MatcherBase, T> { ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} bool match(std::vector const &v) const CATCH_OVERRIDE { return std::find(v.begin(), v.end(), m_comparator) != v.end(); } virtual std::string describe() const CATCH_OVERRIDE { return "Contains: " + Catch::toString( m_comparator ); } T const& m_comparator; }; template struct ContainsMatcher : MatcherBase, std::vector > { ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} bool match(std::vector const &v) const CATCH_OVERRIDE { // !TBD: see note in EqualsMatcher if (m_comparator.size() > v.size()) return false; for (size_t i = 0; i < m_comparator.size(); ++i) if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end()) return false; return true; } virtual std::string describe() const CATCH_OVERRIDE { return "Contains: " + Catch::toString( m_comparator ); } std::vector const& m_comparator; }; template struct EqualsMatcher : MatcherBase, std::vector > { EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} bool match(std::vector const &v) const CATCH_OVERRIDE { // !TBD: This currently works if all elements can be compared using != // - a more general approach would be via a compare template that defaults // to using !=. but could be specialised for, e.g. std::vector etc // - then just call that directly if (m_comparator.size() != v.size()) return false; for (size_t i = 0; i < v.size(); ++i) if (m_comparator[i] != v[i]) return false; return true; } virtual std::string describe() const CATCH_OVERRIDE { return "Equals: " + Catch::toString( m_comparator ); } std::vector const& m_comparator; }; } // namespace Vector // The following functions create the actual matcher objects. // This allows the types to be inferred template Vector::ContainsMatcher Contains( std::vector const& comparator ) { return Vector::ContainsMatcher( comparator ); } template Vector::ContainsElementMatcher VectorContains( T const& comparator ) { return Vector::ContainsElementMatcher( comparator ); } template Vector::EqualsMatcher Equals( std::vector const& comparator ) { return Vector::EqualsMatcher( comparator ); } } // namespace Matchers } // namespace Catch // #included from: internal/catch_interfaces_tag_alias_registry.h #define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED // #included from: catch_tag_alias.h #define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED #include namespace Catch { struct TagAlias { TagAlias( std::string const& _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} std::string tag; SourceLineInfo lineInfo; }; struct RegistrarForTagAliases { RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; } // end namespace Catch #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } // #included from: catch_option.hpp #define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED namespace Catch { // An optional type template class Option { public: Option() : nullableValue( CATCH_NULL ) {} Option( T const& _value ) : nullableValue( new( storage ) T( _value ) ) {} Option( Option const& _other ) : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) {} ~Option() { reset(); } Option& operator= ( Option const& _other ) { if( &_other != this ) { reset(); if( _other ) nullableValue = new( storage ) T( *_other ); } return *this; } Option& operator = ( T const& _value ) { reset(); nullableValue = new( storage ) T( _value ); return *this; } void reset() { if( nullableValue ) nullableValue->~T(); nullableValue = CATCH_NULL; } T& operator*() { return *nullableValue; } T const& operator*() const { return *nullableValue; } T* operator->() { return nullableValue; } const T* operator->() const { return nullableValue; } T valueOr( T const& defaultValue ) const { return nullableValue ? *nullableValue : defaultValue; } bool some() const { return nullableValue != CATCH_NULL; } bool none() const { return nullableValue == CATCH_NULL; } bool operator !() const { return nullableValue == CATCH_NULL; } operator SafeBool::type() const { return SafeBool::makeSafe( some() ); } private: T *nullableValue; union { char storage[sizeof(T)]; // These are here to force alignment for the storage long double dummy1; void (*dummy2)(); long double dummy3; #ifdef CATCH_CONFIG_CPP11_LONG_LONG long long dummy4; #endif }; }; } // end namespace Catch namespace Catch { struct ITagAliasRegistry { virtual ~ITagAliasRegistry(); virtual Option find( std::string const& alias ) const = 0; virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; static ITagAliasRegistry const& get(); }; } // end namespace Catch // These files are included here so the single_include script doesn't put them // in the conditionally compiled sections // #included from: internal/catch_test_case_info.h #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED #include #include #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif namespace Catch { struct ITestCase; struct TestCaseInfo { enum SpecialProperties{ None = 0, IsHidden = 1 << 1, ShouldFail = 1 << 2, MayFail = 1 << 3, Throws = 1 << 4, NonPortable = 1 << 5 }; TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, std::set const& _tags, SourceLineInfo const& _lineInfo ); TestCaseInfo( TestCaseInfo const& other ); friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); bool isHidden() const; bool throws() const; bool okToFail() const; bool expectedToFail() const; std::string name; std::string className; std::string description; std::set tags; std::set lcaseTags; std::string tagsAsString; SourceLineInfo lineInfo; SpecialProperties properties; }; class TestCase : public TestCaseInfo { public: TestCase( ITestCase* testCase, TestCaseInfo const& info ); TestCase( TestCase const& other ); TestCase withName( std::string const& _newName ) const; void invoke() const; TestCaseInfo const& getTestCaseInfo() const; void swap( TestCase& other ); bool operator == ( TestCase const& other ) const; bool operator < ( TestCase const& other ) const; TestCase& operator = ( TestCase const& other ); private: Ptr test; }; TestCase makeTestCase( ITestCase* testCase, std::string const& className, std::string const& name, std::string const& description, SourceLineInfo const& lineInfo ); } #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef __OBJC__ // #included from: internal/catch_objc.hpp #define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED #import #include // NB. Any general catch headers included here must be included // in catch.hpp first to make sure they are included by the single // header for non obj-usage /////////////////////////////////////////////////////////////////////////////// // This protocol is really only here for (self) documenting purposes, since // all its methods are optional. @protocol OcFixture @optional -(void) setUp; -(void) tearDown; @end namespace Catch { class OcMethod : public SharedImpl { public: OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} virtual void invoke() const { id obj = [[m_cls alloc] init]; performOptionalSelector( obj, @selector(setUp) ); performOptionalSelector( obj, m_sel ); performOptionalSelector( obj, @selector(tearDown) ); arcSafeRelease( obj ); } private: virtual ~OcMethod() {} Class m_cls; SEL m_sel; }; namespace Detail{ inline std::string getAnnotation( Class cls, std::string const& annotationName, std::string const& testCaseName ) { NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; SEL sel = NSSelectorFromString( selStr ); arcSafeRelease( selStr ); id value = performOptionalSelector( cls, sel ); if( value ) return [(NSString*)value UTF8String]; return ""; } } inline size_t registerTestMethods() { size_t noTestMethods = 0; int noClasses = objc_getClassList( CATCH_NULL, 0 ); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); objc_getClassList( classes, noClasses ); for( int c = 0; c < noClasses; c++ ) { Class cls = classes[c]; { u_int count; Method* methods = class_copyMethodList( cls, &count ); for( u_int m = 0; m < count ; m++ ) { SEL selector = method_getName(methods[m]); std::string methodName = sel_getName(selector); if( startsWith( methodName, "Catch_TestCase_" ) ) { std::string testCaseName = methodName.substr( 15 ); std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); const char* className = class_getName( cls ); getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); noTestMethods++; } } free(methods); } } return noTestMethods; } namespace Matchers { namespace Impl { namespace NSStringMatchers { struct StringHolder : MatcherBase{ StringHolder( NSString* substr ) : m_substr( [substr copy] ){} StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} StringHolder() { arcSafeRelease( m_substr ); } virtual bool match( NSString* arg ) const CATCH_OVERRIDE { return false; } NSString* m_substr; }; struct Equals : StringHolder { Equals( NSString* substr ) : StringHolder( substr ){} virtual bool match( NSString* str ) const CATCH_OVERRIDE { return (str != nil || m_substr == nil ) && [str isEqualToString:m_substr]; } virtual std::string describe() const CATCH_OVERRIDE { return "equals string: " + Catch::toString( m_substr ); } }; struct Contains : StringHolder { Contains( NSString* substr ) : StringHolder( substr ){} virtual bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location != NSNotFound; } virtual std::string describe() const CATCH_OVERRIDE { return "contains string: " + Catch::toString( m_substr ); } }; struct StartsWith : StringHolder { StartsWith( NSString* substr ) : StringHolder( substr ){} virtual bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == 0; } virtual std::string describe() const CATCH_OVERRIDE { return "starts with: " + Catch::toString( m_substr ); } }; struct EndsWith : StringHolder { EndsWith( NSString* substr ) : StringHolder( substr ){} virtual bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == [str length] - [m_substr length]; } virtual std::string describe() const CATCH_OVERRIDE { return "ends with: " + Catch::toString( m_substr ); } }; } // namespace NSStringMatchers } // namespace Impl inline Impl::NSStringMatchers::Equals Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } inline Impl::NSStringMatchers::Contains Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } inline Impl::NSStringMatchers::StartsWith StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } inline Impl::NSStringMatchers::EndsWith EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } } // namespace Matchers using namespace Matchers; } // namespace Catch /////////////////////////////////////////////////////////////////////////////// #define OC_TEST_CASE( name, desc )\ +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ {\ return @ name; \ }\ +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ { \ return @ desc; \ } \ -(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) #endif #ifdef CATCH_IMPL // !TBD: Move the leak detector code into a separate header #ifdef CATCH_CONFIG_WINDOWS_CRTDBG #include class LeakDetector { public: LeakDetector() { int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); flag |= _CRTDBG_LEAK_CHECK_DF; flag |= _CRTDBG_ALLOC_MEM_DF; _CrtSetDbgFlag(flag); _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); // Change this to leaking allocation's number to break there _CrtSetBreakAlloc(-1); } }; #else class LeakDetector {}; #endif LeakDetector leakDetector; // #included from: internal/catch_impl.hpp #define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED // Collect all the implementation files together here // These are the equivalent of what would usually be cpp files #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wweak-vtables" #endif // #included from: ../catch_session.hpp #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED // #included from: internal/catch_commandline.hpp #define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED // #included from: catch_config.hpp #define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED // #included from: catch_test_spec_parser.hpp #define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif // #included from: catch_test_spec.hpp #define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif // #included from: catch_wildcard_pattern.hpp #define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED #include namespace Catch { class WildcardPattern { enum WildcardPosition { NoWildcard = 0, WildcardAtStart = 1, WildcardAtEnd = 2, WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd }; public: WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) : m_caseSensitivity( caseSensitivity ), m_wildcard( NoWildcard ), m_pattern( adjustCase( pattern ) ) { if( startsWith( m_pattern, '*' ) ) { m_pattern = m_pattern.substr( 1 ); m_wildcard = WildcardAtStart; } if( endsWith( m_pattern, '*' ) ) { m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); } } virtual ~WildcardPattern(); virtual bool matches( std::string const& str ) const { switch( m_wildcard ) { case NoWildcard: return m_pattern == adjustCase( str ); case WildcardAtStart: return endsWith( adjustCase( str ), m_pattern ); case WildcardAtEnd: return startsWith( adjustCase( str ), m_pattern ); case WildcardAtBothEnds: return contains( adjustCase( str ), m_pattern ); } #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif throw std::logic_error( "Unknown enum" ); #ifdef __clang__ #pragma clang diagnostic pop #endif } private: std::string adjustCase( std::string const& str ) const { return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; } CaseSensitive::Choice m_caseSensitivity; WildcardPosition m_wildcard; std::string m_pattern; }; } #include #include namespace Catch { class TestSpec { struct Pattern : SharedImpl<> { virtual ~Pattern(); virtual bool matches( TestCaseInfo const& testCase ) const = 0; }; class NamePattern : public Pattern { public: NamePattern( std::string const& name ) : m_wildcardPattern( toLower( name ), CaseSensitive::No ) {} virtual ~NamePattern(); virtual bool matches( TestCaseInfo const& testCase ) const { return m_wildcardPattern.matches( toLower( testCase.name ) ); } private: WildcardPattern m_wildcardPattern; }; class TagPattern : public Pattern { public: TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} virtual ~TagPattern(); virtual bool matches( TestCaseInfo const& testCase ) const { return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); } private: std::string m_tag; }; class ExcludedPattern : public Pattern { public: ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} virtual ~ExcludedPattern(); virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } private: Ptr m_underlyingPattern; }; struct Filter { std::vector > m_patterns; bool matches( TestCaseInfo const& testCase ) const { // All patterns in a filter must match for the filter to be a match for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) { if( !(*it)->matches( testCase ) ) return false; } return true; } }; public: bool hasFilters() const { return !m_filters.empty(); } bool matches( TestCaseInfo const& testCase ) const { // A TestSpec matches if any filter matches for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) if( it->matches( testCase ) ) return true; return false; } private: std::vector m_filters; friend class TestSpecParser; }; } #ifdef __clang__ #pragma clang diagnostic pop #endif namespace Catch { class TestSpecParser { enum Mode{ None, Name, QuotedName, Tag, EscapedName }; Mode m_mode; bool m_exclusion; std::size_t m_start, m_pos; std::string m_arg; std::vector m_escapeChars; TestSpec::Filter m_currentFilter; TestSpec m_testSpec; ITagAliasRegistry const* m_tagAliases; public: TestSpecParser( ITagAliasRegistry const& tagAliases ) :m_mode(None), m_exclusion(false), m_start(0), m_pos(0), m_tagAliases( &tagAliases ) {} TestSpecParser& parse( std::string const& arg ) { m_mode = None; m_exclusion = false; m_start = std::string::npos; m_arg = m_tagAliases->expandAliases( arg ); m_escapeChars.clear(); for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) visitChar( m_arg[m_pos] ); if( m_mode == Name ) addPattern(); return *this; } TestSpec testSpec() { addFilter(); return m_testSpec; } private: void visitChar( char c ) { if( m_mode == None ) { switch( c ) { case ' ': return; case '~': m_exclusion = true; return; case '[': return startNewMode( Tag, ++m_pos ); case '"': return startNewMode( QuotedName, ++m_pos ); case '\\': return escape(); default: startNewMode( Name, m_pos ); break; } } if( m_mode == Name ) { if( c == ',' ) { addPattern(); addFilter(); } else if( c == '[' ) { if( subString() == "exclude:" ) m_exclusion = true; else addPattern(); startNewMode( Tag, ++m_pos ); } else if( c == '\\' ) escape(); } else if( m_mode == EscapedName ) m_mode = Name; else if( m_mode == QuotedName && c == '"' ) addPattern(); else if( m_mode == Tag && c == ']' ) addPattern(); } void startNewMode( Mode mode, std::size_t start ) { m_mode = mode; m_start = start; } void escape() { if( m_mode == None ) m_start = m_pos; m_mode = EscapedName; m_escapeChars.push_back( m_pos ); } std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } template void addPattern() { std::string token = subString(); for( size_t i = 0; i < m_escapeChars.size(); ++i ) token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); m_escapeChars.clear(); if( startsWith( token, "exclude:" ) ) { m_exclusion = true; token = token.substr( 8 ); } if( !token.empty() ) { Ptr pattern = new T( token ); if( m_exclusion ) pattern = new TestSpec::ExcludedPattern( pattern ); m_currentFilter.m_patterns.push_back( pattern ); } m_exclusion = false; m_mode = None; } void addFilter() { if( !m_currentFilter.m_patterns.empty() ) { m_testSpec.m_filters.push_back( m_currentFilter ); m_currentFilter = TestSpec::Filter(); } } }; inline TestSpec parseTestSpec( std::string const& arg ) { return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); } } // namespace Catch #ifdef __clang__ #pragma clang diagnostic pop #endif // #included from: catch_interfaces_config.h #define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED #include #include #include namespace Catch { struct Verbosity { enum Level { NoOutput = 0, Quiet, Normal }; }; struct WarnAbout { enum What { Nothing = 0x00, NoAssertions = 0x01 }; }; struct ShowDurations { enum OrNot { DefaultForReporter, Always, Never }; }; struct RunTests { enum InWhatOrder { InDeclarationOrder, InLexicographicalOrder, InRandomOrder }; }; struct UseColour { enum YesOrNo { Auto, Yes, No }; }; class TestSpec; struct IConfig : IShared { virtual ~IConfig(); virtual bool allowThrows() const = 0; virtual std::ostream& stream() const = 0; virtual std::string name() const = 0; virtual bool includeSuccessfulResults() const = 0; virtual bool shouldDebugBreak() const = 0; virtual bool warnAboutMissingAssertions() const = 0; virtual int abortAfter() const = 0; virtual bool showInvisibles() const = 0; virtual ShowDurations::OrNot showDurations() const = 0; virtual TestSpec const& testSpec() const = 0; virtual RunTests::InWhatOrder runOrder() const = 0; virtual unsigned int rngSeed() const = 0; virtual UseColour::YesOrNo useColour() const = 0; virtual std::vector const& getSectionsToRun() const = 0; }; } // #included from: catch_stream.h #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED // #included from: catch_streambuf.h #define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED #include namespace Catch { class StreamBufBase : public std::streambuf { public: virtual ~StreamBufBase() CATCH_NOEXCEPT; }; } #include #include #include #include namespace Catch { std::ostream& cout(); std::ostream& cerr(); std::ostream& clog(); struct IStream { virtual ~IStream() CATCH_NOEXCEPT; virtual std::ostream& stream() const = 0; }; class FileStream : public IStream { mutable std::ofstream m_ofs; public: FileStream( std::string const& filename ); virtual ~FileStream() CATCH_NOEXCEPT; public: // IStream virtual std::ostream& stream() const CATCH_OVERRIDE; }; class CoutStream : public IStream { mutable std::ostream m_os; public: CoutStream(); virtual ~CoutStream() CATCH_NOEXCEPT; public: // IStream virtual std::ostream& stream() const CATCH_OVERRIDE; }; class DebugOutStream : public IStream { CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf; mutable std::ostream m_os; public: DebugOutStream(); virtual ~DebugOutStream() CATCH_NOEXCEPT; public: // IStream virtual std::ostream& stream() const CATCH_OVERRIDE; }; } #include #include #include #include #ifndef CATCH_CONFIG_CONSOLE_WIDTH #define CATCH_CONFIG_CONSOLE_WIDTH 80 #endif namespace Catch { struct ConfigData { ConfigData() : listTests( false ), listTags( false ), listReporters( false ), listTestNamesOnly( false ), listExtraInfo( false ), showSuccessfulTests( false ), shouldDebugBreak( false ), noThrow( false ), showHelp( false ), showInvisibles( false ), filenamesAsTags( false ), abortAfter( -1 ), rngSeed( 0 ), verbosity( Verbosity::Normal ), warnings( WarnAbout::Nothing ), showDurations( ShowDurations::DefaultForReporter ), runOrder( RunTests::InDeclarationOrder ), useColour( UseColour::Auto ) {} bool listTests; bool listTags; bool listReporters; bool listTestNamesOnly; bool listExtraInfo; bool showSuccessfulTests; bool shouldDebugBreak; bool noThrow; bool showHelp; bool showInvisibles; bool filenamesAsTags; int abortAfter; unsigned int rngSeed; Verbosity::Level verbosity; WarnAbout::What warnings; ShowDurations::OrNot showDurations; RunTests::InWhatOrder runOrder; UseColour::YesOrNo useColour; std::string outputFilename; std::string name; std::string processName; std::vector reporterNames; std::vector testsOrTags; std::vector sectionsToRun; }; class Config : public SharedImpl { private: Config( Config const& other ); Config& operator = ( Config const& other ); virtual void dummy(); public: Config() {} Config( ConfigData const& data ) : m_data( data ), m_stream( openStream() ) { if( !data.testsOrTags.empty() ) { TestSpecParser parser( ITagAliasRegistry::get() ); for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) parser.parse( data.testsOrTags[i] ); m_testSpec = parser.testSpec(); } } virtual ~Config() {} std::string const& getFilename() const { return m_data.outputFilename ; } bool listTests() const { return m_data.listTests; } bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } bool listTags() const { return m_data.listTags; } bool listReporters() const { return m_data.listReporters; } bool listExtraInfo() const { return m_data.listExtraInfo; } std::string getProcessName() const { return m_data.processName; } std::vector const& getReporterNames() const { return m_data.reporterNames; } std::vector const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; } virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; } bool showHelp() const { return m_data.showHelp; } // IConfig interface virtual bool allowThrows() const CATCH_OVERRIDE { return !m_data.noThrow; } virtual std::ostream& stream() const CATCH_OVERRIDE { return m_stream->stream(); } virtual std::string name() const CATCH_OVERRIDE { return m_data.name.empty() ? m_data.processName : m_data.name; } virtual bool includeSuccessfulResults() const CATCH_OVERRIDE { return m_data.showSuccessfulTests; } virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE { return m_data.warnings & WarnAbout::NoAssertions; } virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; } virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE { return m_data.runOrder; } virtual unsigned int rngSeed() const CATCH_OVERRIDE { return m_data.rngSeed; } virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE { return m_data.useColour; } virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; } virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; } virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; } private: IStream const* openStream() { if( m_data.outputFilename.empty() ) return new CoutStream(); else if( m_data.outputFilename[0] == '%' ) { if( m_data.outputFilename == "%debug" ) return new DebugOutStream(); else throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); } else return new FileStream( m_data.outputFilename ); } ConfigData m_data; CATCH_AUTO_PTR( IStream const ) m_stream; TestSpec m_testSpec; }; } // end namespace Catch // #included from: catch_clara.h #define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED // Use Catch's value for console width (store Clara's off to the side, if present) #ifdef CLARA_CONFIG_CONSOLE_WIDTH #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH #undef CLARA_CONFIG_CONSOLE_WIDTH #endif #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH // Declare Clara inside the Catch namespace #define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { // #included from: ../external/clara.h // Version 0.0.2.4 // Only use header guard if we are not using an outer namespace #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) #ifndef STITCH_CLARA_OPEN_NAMESPACE #define TWOBLUECUBES_CLARA_H_INCLUDED #define STITCH_CLARA_OPEN_NAMESPACE #define STITCH_CLARA_CLOSE_NAMESPACE #else #define STITCH_CLARA_CLOSE_NAMESPACE } #endif #define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE // ----------- #included from tbc_text_format.h ----------- // Only use header guard if we are not using an outer namespace #if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) #ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE #define TBC_TEXT_FORMAT_H_INCLUDED #endif #include #include #include #include #include // Use optional outer namespace #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { #endif namespace Tbc { #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; #else const unsigned int consoleWidth = 80; #endif struct TextAttributes { TextAttributes() : initialIndent( std::string::npos ), indent( 0 ), width( consoleWidth-1 ), tabChar( '\t' ) {} TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } std::size_t initialIndent; // indent of first line, or npos std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos std::size_t width; // maximum width of text, including indent. Longer text will wrap char tabChar; // If this char is seen the indent is changed to current pos }; class Text { public: Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) : attr( _attr ) { std::string wrappableChars = " [({.,/|\\-"; std::size_t indent = _attr.initialIndent != std::string::npos ? _attr.initialIndent : _attr.indent; std::string remainder = _str; while( !remainder.empty() ) { if( lines.size() >= 1000 ) { lines.push_back( "... message truncated due to excessive size" ); return; } std::size_t tabPos = std::string::npos; std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); std::size_t pos = remainder.find_first_of( '\n' ); if( pos <= width ) { width = pos; } pos = remainder.find_last_of( _attr.tabChar, width ); if( pos != std::string::npos ) { tabPos = pos; if( remainder[width] == '\n' ) width--; remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); } if( width == remainder.size() ) { spliceLine( indent, remainder, width ); } else if( remainder[width] == '\n' ) { spliceLine( indent, remainder, width ); if( width <= 1 || remainder.size() != 1 ) remainder = remainder.substr( 1 ); indent = _attr.indent; } else { pos = remainder.find_last_of( wrappableChars, width ); if( pos != std::string::npos && pos > 0 ) { spliceLine( indent, remainder, pos ); if( remainder[0] == ' ' ) remainder = remainder.substr( 1 ); } else { spliceLine( indent, remainder, width-1 ); lines.back() += "-"; } if( lines.size() == 1 ) indent = _attr.indent; if( tabPos != std::string::npos ) indent += tabPos; } } } void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); _remainder = _remainder.substr( _pos ); } typedef std::vector::const_iterator const_iterator; const_iterator begin() const { return lines.begin(); } const_iterator end() const { return lines.end(); } std::string const& last() const { return lines.back(); } std::size_t size() const { return lines.size(); } std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } std::string toString() const { std::ostringstream oss; oss << *this; return oss.str(); } friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); it != itEnd; ++it ) { if( it != _text.begin() ) _stream << "\n"; _stream << *it; } return _stream; } private: std::string str; TextAttributes attr; std::vector lines; }; } // end namespace Tbc #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE } // end outer namespace #endif #endif // TBC_TEXT_FORMAT_H_INCLUDED // ----------- end of #include from tbc_text_format.h ----------- // ........... back in clara.h #undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE // ----------- #included from clara_compilers.h ----------- #ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED #define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED // Detect a number of compiler features - mostly C++11/14 conformance - by compiler // The following features are defined: // // CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? // CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? // CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods // CLARA_CONFIG_CPP11_OVERRIDE : is override supported? // CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) // CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? // CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? // In general each macro has a _NO_ form // (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. // All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 #ifdef __clang__ #if __has_feature(cxx_nullptr) #define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR #endif #if __has_feature(cxx_noexcept) #define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT #endif #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// // GCC #ifdef __GNUC__ #if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) #define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR #endif // - otherwise more recent versions define __cplusplus >= 201103L // and will get picked up below #endif // __GNUC__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ #ifdef _MSC_VER #if (_MSC_VER >= 1600) #define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR #define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR #endif #if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) #define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT #define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS #endif #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// // C++ language feature support // catch all support for C++11 #if defined(__cplusplus) && __cplusplus >= 201103L #define CLARA_CPP11_OR_GREATER #if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) #define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR #endif #ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT #define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT #endif #ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS #define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS #endif #if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) #define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE #endif #if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) #define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR #endif #endif // __cplusplus >= 201103L // Now set the actual defines based on the above + anything the user has configured #if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) #define CLARA_CONFIG_CPP11_NULLPTR #endif #if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) #define CLARA_CONFIG_CPP11_NOEXCEPT #endif #if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) #define CLARA_CONFIG_CPP11_GENERATED_METHODS #endif #if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) #define CLARA_CONFIG_CPP11_OVERRIDE #endif #if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) #define CLARA_CONFIG_CPP11_UNIQUE_PTR #endif // noexcept support: #if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) #define CLARA_NOEXCEPT noexcept # define CLARA_NOEXCEPT_IS(x) noexcept(x) #else #define CLARA_NOEXCEPT throw() # define CLARA_NOEXCEPT_IS(x) #endif // nullptr support #ifdef CLARA_CONFIG_CPP11_NULLPTR #define CLARA_NULL nullptr #else #define CLARA_NULL NULL #endif // override support #ifdef CLARA_CONFIG_CPP11_OVERRIDE #define CLARA_OVERRIDE override #else #define CLARA_OVERRIDE #endif // unique_ptr support #ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR # define CLARA_AUTO_PTR( T ) std::unique_ptr #else # define CLARA_AUTO_PTR( T ) std::auto_ptr #endif #endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED // ----------- end of #include from clara_compilers.h ----------- // ........... back in clara.h #include #include #include #if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) #define CLARA_PLATFORM_WINDOWS #endif // Use optional outer namespace #ifdef STITCH_CLARA_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE #endif namespace Clara { struct UnpositionalTag {}; extern UnpositionalTag _; #ifdef CLARA_CONFIG_MAIN UnpositionalTag _; #endif namespace Detail { #ifdef CLARA_CONSOLE_WIDTH const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; #else const unsigned int consoleWidth = 80; #endif using namespace Tbc; inline bool startsWith( std::string const& str, std::string const& prefix ) { return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; } template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct IsBool { static const bool value = false; }; template<> struct IsBool { static const bool value = true; }; template void convertInto( std::string const& _source, T& _dest ) { std::stringstream ss; ss << _source; ss >> _dest; if( ss.fail() ) throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); } inline void convertInto( std::string const& _source, std::string& _dest ) { _dest = _source; } char toLowerCh(char c) { return static_cast( std::tolower( c ) ); } inline void convertInto( std::string const& _source, bool& _dest ) { std::string sourceLC = _source; std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh ); if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) _dest = true; else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) _dest = false; else throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); } template struct IArgFunction { virtual ~IArgFunction() {} #ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS IArgFunction() = default; IArgFunction( IArgFunction const& ) = default; #endif virtual void set( ConfigT& config, std::string const& value ) const = 0; virtual bool takesArg() const = 0; virtual IArgFunction* clone() const = 0; }; template class BoundArgFunction { public: BoundArgFunction() : functionObj( CLARA_NULL ) {} BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} BoundArgFunction& operator = ( BoundArgFunction const& other ) { IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; delete functionObj; functionObj = newFunctionObj; return *this; } ~BoundArgFunction() { delete functionObj; } void set( ConfigT& config, std::string const& value ) const { functionObj->set( config, value ); } bool takesArg() const { return functionObj->takesArg(); } bool isSet() const { return functionObj != CLARA_NULL; } private: IArgFunction* functionObj; }; template struct NullBinder : IArgFunction{ virtual void set( C&, std::string const& ) const {} virtual bool takesArg() const { return true; } virtual IArgFunction* clone() const { return new NullBinder( *this ); } }; template struct BoundDataMember : IArgFunction{ BoundDataMember( M C::* _member ) : member( _member ) {} virtual void set( C& p, std::string const& stringValue ) const { convertInto( stringValue, p.*member ); } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } M C::* member; }; template struct BoundUnaryMethod : IArgFunction{ BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} virtual void set( C& p, std::string const& stringValue ) const { typename RemoveConstRef::type value; convertInto( stringValue, value ); (p.*member)( value ); } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } void (C::*member)( M ); }; template struct BoundNullaryMethod : IArgFunction{ BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} virtual void set( C& p, std::string const& stringValue ) const { bool value; convertInto( stringValue, value ); if( value ) (p.*member)(); } virtual bool takesArg() const { return false; } virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } void (C::*member)(); }; template struct BoundUnaryFunction : IArgFunction{ BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} virtual void set( C& obj, std::string const& stringValue ) const { bool value; convertInto( stringValue, value ); if( value ) function( obj ); } virtual bool takesArg() const { return false; } virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } void (*function)( C& ); }; template struct BoundBinaryFunction : IArgFunction{ BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} virtual void set( C& obj, std::string const& stringValue ) const { typename RemoveConstRef::type value; convertInto( stringValue, value ); function( obj, value ); } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } void (*function)( C&, T ); }; } // namespace Detail inline std::vector argsToVector( int argc, char const* const* const argv ) { std::vector args( static_cast( argc ) ); for( std::size_t i = 0; i < static_cast( argc ); ++i ) args[i] = argv[i]; return args; } class Parser { enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional }; Mode mode; std::size_t from; bool inQuotes; public: struct Token { enum Type { Positional, ShortOpt, LongOpt }; Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} Type type; std::string data; }; Parser() : mode( None ), from( 0 ), inQuotes( false ){} void parseIntoTokens( std::vector const& args, std::vector& tokens ) { const std::string doubleDash = "--"; for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i ) parseIntoTokens( args[i], tokens); } void parseIntoTokens( std::string const& arg, std::vector& tokens ) { for( std::size_t i = 0; i < arg.size(); ++i ) { char c = arg[i]; if( c == '"' ) inQuotes = !inQuotes; mode = handleMode( i, c, arg, tokens ); } mode = handleMode( arg.size(), '\0', arg, tokens ); } Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { switch( mode ) { case None: return handleNone( i, c ); case MaybeShortOpt: return handleMaybeShortOpt( i, c ); case ShortOpt: case LongOpt: case SlashOpt: return handleOpt( i, c, arg, tokens ); case Positional: return handlePositional( i, c, arg, tokens ); default: throw std::logic_error( "Unknown mode" ); } } Mode handleNone( std::size_t i, char c ) { if( inQuotes ) { from = i; return Positional; } switch( c ) { case '-': return MaybeShortOpt; #ifdef CLARA_PLATFORM_WINDOWS case '/': from = i+1; return SlashOpt; #endif default: from = i; return Positional; } } Mode handleMaybeShortOpt( std::size_t i, char c ) { switch( c ) { case '-': from = i+1; return LongOpt; default: from = i; return ShortOpt; } } Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { if( std::string( ":=\0", 3 ).find( c ) == std::string::npos ) return mode; std::string optName = arg.substr( from, i-from ); if( mode == ShortOpt ) for( std::size_t j = 0; j < optName.size(); ++j ) tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) ); else if( mode == SlashOpt && optName.size() == 1 ) tokens.push_back( Token( Token::ShortOpt, optName ) ); else tokens.push_back( Token( Token::LongOpt, optName ) ); return None; } Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos ) return mode; std::string data = arg.substr( from, i-from ); tokens.push_back( Token( Token::Positional, data ) ); return None; } }; template struct CommonArgProperties { CommonArgProperties() {} CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} Detail::BoundArgFunction boundField; std::string description; std::string detail; std::string placeholder; // Only value if boundField takes an arg bool takesArg() const { return !placeholder.empty(); } void validate() const { if( !boundField.isSet() ) throw std::logic_error( "option not bound" ); } }; struct OptionArgProperties { std::vector shortNames; std::string longName; bool hasShortName( std::string const& shortName ) const { return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); } bool hasLongName( std::string const& _longName ) const { return _longName == longName; } }; struct PositionalArgProperties { PositionalArgProperties() : position( -1 ) {} int position; // -1 means non-positional (floating) bool isFixedPositional() const { return position != -1; } }; template class CommandLine { struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { Arg() {} Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} using CommonArgProperties::placeholder; // !TBD std::string dbgName() const { if( !longName.empty() ) return "--" + longName; if( !shortNames.empty() ) return "-" + shortNames[0]; return "positional args"; } std::string commands() const { std::ostringstream oss; bool first = true; std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); for(; it != itEnd; ++it ) { if( first ) first = false; else oss << ", "; oss << "-" << *it; } if( !longName.empty() ) { if( !first ) oss << ", "; oss << "--" << longName; } if( !placeholder.empty() ) oss << " <" << placeholder << ">"; return oss.str(); } }; typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; friend void addOptName( Arg& arg, std::string const& optName ) { if( optName.empty() ) return; if( Detail::startsWith( optName, "--" ) ) { if( !arg.longName.empty() ) throw std::logic_error( "Only one long opt may be specified. '" + arg.longName + "' already specified, now attempting to add '" + optName + "'" ); arg.longName = optName.substr( 2 ); } else if( Detail::startsWith( optName, "-" ) ) arg.shortNames.push_back( optName.substr( 1 ) ); else throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); } friend void setPositionalArg( Arg& arg, int position ) { arg.position = position; } class ArgBuilder { public: ArgBuilder( Arg* arg ) : m_arg( arg ) {} // Bind a non-boolean data member (requires placeholder string) template void bind( M C::* field, std::string const& placeholder ) { m_arg->boundField = new Detail::BoundDataMember( field ); m_arg->placeholder = placeholder; } // Bind a boolean data member (no placeholder required) template void bind( bool C::* field ) { m_arg->boundField = new Detail::BoundDataMember( field ); } // Bind a method taking a single, non-boolean argument (requires a placeholder string) template void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); m_arg->placeholder = placeholder; } // Bind a method taking a single, boolean argument (no placeholder string required) template void bind( void (C::* unaryMethod)( bool ) ) { m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); } // Bind a method that takes no arguments (will be called if opt is present) template void bind( void (C::* nullaryMethod)() ) { m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); } // Bind a free function taking a single argument - the object to operate on (no placeholder string required) template void bind( void (* unaryFunction)( C& ) ) { m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); } // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) template void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); m_arg->placeholder = placeholder; } ArgBuilder& describe( std::string const& description ) { m_arg->description = description; return *this; } ArgBuilder& detail( std::string const& detail ) { m_arg->detail = detail; return *this; } protected: Arg* m_arg; }; class OptBuilder : public ArgBuilder { public: OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} OptBuilder& operator[]( std::string const& optName ) { addOptName( *ArgBuilder::m_arg, optName ); return *this; } }; public: CommandLine() : m_boundProcessName( new Detail::NullBinder() ), m_highestSpecifiedArgPosition( 0 ), m_throwOnUnrecognisedTokens( false ) {} CommandLine( CommandLine const& other ) : m_boundProcessName( other.m_boundProcessName ), m_options ( other.m_options ), m_positionalArgs( other.m_positionalArgs ), m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) { if( other.m_floatingArg.get() ) m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); } CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { m_throwOnUnrecognisedTokens = shouldThrow; return *this; } OptBuilder operator[]( std::string const& optName ) { m_options.push_back( Arg() ); addOptName( m_options.back(), optName ); OptBuilder builder( &m_options.back() ); return builder; } ArgBuilder operator[]( int position ) { m_positionalArgs.insert( std::make_pair( position, Arg() ) ); if( position > m_highestSpecifiedArgPosition ) m_highestSpecifiedArgPosition = position; setPositionalArg( m_positionalArgs[position], position ); ArgBuilder builder( &m_positionalArgs[position] ); return builder; } // Invoke this with the _ instance ArgBuilder operator[]( UnpositionalTag ) { if( m_floatingArg.get() ) throw std::logic_error( "Only one unpositional argument can be added" ); m_floatingArg.reset( new Arg() ); ArgBuilder builder( m_floatingArg.get() ); return builder; } template void bindProcessName( M C::* field ) { m_boundProcessName = new Detail::BoundDataMember( field ); } template void bindProcessName( void (C::*_unaryMethod)( M ) ) { m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); } void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; std::size_t maxWidth = 0; for( it = itBegin; it != itEnd; ++it ) maxWidth = (std::max)( maxWidth, it->commands().size() ); for( it = itBegin; it != itEnd; ++it ) { Detail::Text usage( it->commands(), Detail::TextAttributes() .setWidth( maxWidth+indent ) .setIndent( indent ) ); Detail::Text desc( it->description, Detail::TextAttributes() .setWidth( width - maxWidth - 3 ) ); for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { std::string usageCol = i < usage.size() ? usage[i] : ""; os << usageCol; if( i < desc.size() && !desc[i].empty() ) os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) << desc[i]; os << "\n"; } } } std::string optUsage() const { std::ostringstream oss; optUsage( oss ); return oss.str(); } void argSynopsis( std::ostream& os ) const { for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { if( i > 1 ) os << " "; typename std::map::const_iterator it = m_positionalArgs.find( i ); if( it != m_positionalArgs.end() ) os << "<" << it->second.placeholder << ">"; else if( m_floatingArg.get() ) os << "<" << m_floatingArg->placeholder << ">"; else throw std::logic_error( "non consecutive positional arguments with no floating args" ); } // !TBD No indication of mandatory args if( m_floatingArg.get() ) { if( m_highestSpecifiedArgPosition > 1 ) os << " "; os << "[<" << m_floatingArg->placeholder << "> ...]"; } } std::string argSynopsis() const { std::ostringstream oss; argSynopsis( oss ); return oss.str(); } void usage( std::ostream& os, std::string const& procName ) const { validate(); os << "usage:\n " << procName << " "; argSynopsis( os ); if( !m_options.empty() ) { os << " [options]\n\nwhere options are: \n"; optUsage( os, 2 ); } os << "\n"; } std::string usage( std::string const& procName ) const { std::ostringstream oss; usage( oss, procName ); return oss.str(); } ConfigT parse( std::vector const& args ) const { ConfigT config; parseInto( args, config ); return config; } std::vector parseInto( std::vector const& args, ConfigT& config ) const { std::string processName = args.empty() ? std::string() : args[0]; std::size_t lastSlash = processName.find_last_of( "/\\" ); if( lastSlash != std::string::npos ) processName = processName.substr( lastSlash+1 ); m_boundProcessName.set( config, processName ); std::vector tokens; Parser parser; parser.parseIntoTokens( args, tokens ); return populate( tokens, config ); } std::vector populate( std::vector const& tokens, ConfigT& config ) const { validate(); std::vector unusedTokens = populateOptions( tokens, config ); unusedTokens = populateFixedArgs( unusedTokens, config ); unusedTokens = populateFloatingArgs( unusedTokens, config ); return unusedTokens; } std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { std::vector unusedTokens; std::vector errors; for( std::size_t i = 0; i < tokens.size(); ++i ) { Parser::Token const& token = tokens[i]; typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); for(; it != itEnd; ++it ) { Arg const& arg = *it; try { if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { if( arg.takesArg() ) { if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) errors.push_back( "Expected argument to option: " + token.data ); else arg.boundField.set( config, tokens[++i].data ); } else { arg.boundField.set( config, "true" ); } break; } } catch( std::exception& ex ) { errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); } } if( it == itEnd ) { if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) unusedTokens.push_back( token ); else if( errors.empty() && m_throwOnUnrecognisedTokens ) errors.push_back( "unrecognised option: " + token.data ); } } if( !errors.empty() ) { std::ostringstream oss; for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); it != itEnd; ++it ) { if( it != errors.begin() ) oss << "\n"; oss << *it; } throw std::runtime_error( oss.str() ); } return unusedTokens; } std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { std::vector unusedTokens; int position = 1; for( std::size_t i = 0; i < tokens.size(); ++i ) { Parser::Token const& token = tokens[i]; typename std::map::const_iterator it = m_positionalArgs.find( position ); if( it != m_positionalArgs.end() ) it->second.boundField.set( config, token.data ); else unusedTokens.push_back( token ); if( token.type == Parser::Token::Positional ) position++; } return unusedTokens; } std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { if( !m_floatingArg.get() ) return tokens; std::vector unusedTokens; for( std::size_t i = 0; i < tokens.size(); ++i ) { Parser::Token const& token = tokens[i]; if( token.type == Parser::Token::Positional ) m_floatingArg->boundField.set( config, token.data ); else unusedTokens.push_back( token ); } return unusedTokens; } void validate() const { if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) throw std::logic_error( "No options or arguments specified" ); for( typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); it != itEnd; ++it ) it->validate(); } private: Detail::BoundArgFunction m_boundProcessName; std::vector m_options; std::map m_positionalArgs; ArgAutoPtr m_floatingArg; int m_highestSpecifiedArgPosition; bool m_throwOnUnrecognisedTokens; }; } // end namespace Clara STITCH_CLARA_CLOSE_NAMESPACE #undef STITCH_CLARA_OPEN_NAMESPACE #undef STITCH_CLARA_CLOSE_NAMESPACE #endif // TWOBLUECUBES_CLARA_H_INCLUDED #undef STITCH_CLARA_OPEN_NAMESPACE // Restore Clara's value for console width, if present #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #endif #include #include namespace Catch { inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } inline void abortAfterX( ConfigData& config, int x ) { if( x < 1 ) throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); config.abortAfter = x; } inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); } inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } inline void addWarning( ConfigData& config, std::string const& _warning ) { if( _warning == "NoAssertions" ) config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); else throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' ); } inline void setOrder( ConfigData& config, std::string const& order ) { if( startsWith( "declared", order ) ) config.runOrder = RunTests::InDeclarationOrder; else if( startsWith( "lexical", order ) ) config.runOrder = RunTests::InLexicographicalOrder; else if( startsWith( "random", order ) ) config.runOrder = RunTests::InRandomOrder; else throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' ); } inline void setRngSeed( ConfigData& config, std::string const& seed ) { if( seed == "time" ) { config.rngSeed = static_cast( std::time(0) ); } else { std::stringstream ss; ss << seed; ss >> config.rngSeed; if( ss.fail() ) throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" ); } } inline void setVerbosity( ConfigData& config, int level ) { // !TBD: accept strings? config.verbosity = static_cast( level ); } inline void setShowDurations( ConfigData& config, bool _showDurations ) { config.showDurations = _showDurations ? ShowDurations::Always : ShowDurations::Never; } inline void setUseColour( ConfigData& config, std::string const& value ) { std::string mode = toLower( value ); if( mode == "yes" ) config.useColour = UseColour::Yes; else if( mode == "no" ) config.useColour = UseColour::No; else if( mode == "auto" ) config.useColour = UseColour::Auto; else throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); } inline void forceColour( ConfigData& config ) { config.useColour = UseColour::Yes; } inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { std::ifstream f( _filename.c_str() ); if( !f.is_open() ) throw std::domain_error( "Unable to load input file: " + _filename ); std::string line; while( std::getline( f, line ) ) { line = trim(line); if( !line.empty() && !startsWith( line, '#' ) ) { if( !startsWith( line, '"' ) ) line = '"' + line + '"'; addTestOrTags( config, line + ',' ); } } } inline Clara::CommandLine makeCommandLineParser() { using namespace Clara; CommandLine cli; cli.bindProcessName( &ConfigData::processName ); cli["-?"]["-h"]["--help"] .describe( "display usage information" ) .bind( &ConfigData::showHelp ); cli["-l"]["--list-tests"] .describe( "list all/matching test cases" ) .bind( &ConfigData::listTests ); cli["-t"]["--list-tags"] .describe( "list all/matching tags" ) .bind( &ConfigData::listTags ); cli["-s"]["--success"] .describe( "include successful tests in output" ) .bind( &ConfigData::showSuccessfulTests ); cli["-b"]["--break"] .describe( "break into debugger on failure" ) .bind( &ConfigData::shouldDebugBreak ); cli["-e"]["--nothrow"] .describe( "skip exception tests" ) .bind( &ConfigData::noThrow ); cli["-i"]["--invisibles"] .describe( "show invisibles (tabs, newlines)" ) .bind( &ConfigData::showInvisibles ); cli["-o"]["--out"] .describe( "output filename" ) .bind( &ConfigData::outputFilename, "filename" ); cli["-r"]["--reporter"] // .placeholder( "name[:filename]" ) .describe( "reporter to use (defaults to console)" ) .bind( &addReporterName, "name" ); cli["-n"]["--name"] .describe( "suite name" ) .bind( &ConfigData::name, "name" ); cli["-a"]["--abort"] .describe( "abort at first failure" ) .bind( &abortAfterFirst ); cli["-x"]["--abortx"] .describe( "abort after x failures" ) .bind( &abortAfterX, "no. failures" ); cli["-w"]["--warn"] .describe( "enable warnings" ) .bind( &addWarning, "warning name" ); // - needs updating if reinstated // cli.into( &setVerbosity ) // .describe( "level of verbosity (0=no output)" ) // .shortOpt( "v") // .longOpt( "verbosity" ) // .placeholder( "level" ); cli[_] .describe( "which test or tests to use" ) .bind( &addTestOrTags, "test name, pattern or tags" ); cli["-d"]["--durations"] .describe( "show test durations" ) .bind( &setShowDurations, "yes|no" ); cli["-f"]["--input-file"] .describe( "load test names to run from a file" ) .bind( &loadTestNamesFromFile, "filename" ); cli["-#"]["--filenames-as-tags"] .describe( "adds a tag for the filename" ) .bind( &ConfigData::filenamesAsTags ); cli["-c"]["--section"] .describe( "specify section to run" ) .bind( &addSectionToRun, "section name" ); // Less common commands which don't have a short form cli["--list-test-names-only"] .describe( "list all/matching test cases names only" ) .bind( &ConfigData::listTestNamesOnly ); cli["--list-extra-info"] .describe( "list all/matching test cases with more info" ) .bind( &ConfigData::listExtraInfo ); cli["--list-reporters"] .describe( "list all reporters" ) .bind( &ConfigData::listReporters ); cli["--order"] .describe( "test case order (defaults to decl)" ) .bind( &setOrder, "decl|lex|rand" ); cli["--rng-seed"] .describe( "set a specific seed for random numbers" ) .bind( &setRngSeed, "'time'|number" ); cli["--force-colour"] .describe( "force colourised output (deprecated)" ) .bind( &forceColour ); cli["--use-colour"] .describe( "should output be colourised" ) .bind( &setUseColour, "yes|no" ); return cli; } } // end namespace Catch // #included from: internal/catch_list.hpp #define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED // #included from: catch_text.h #define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED #define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH #define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch // #included from: ../external/tbc_text_format.h // Only use header guard if we are not using an outer namespace #ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE # ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED # ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED # define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED # endif # else # define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED # endif #endif #ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED #include #include #include // Use optional outer namespace #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { #endif namespace Tbc { #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; #else const unsigned int consoleWidth = 80; #endif struct TextAttributes { TextAttributes() : initialIndent( std::string::npos ), indent( 0 ), width( consoleWidth-1 ) {} TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } std::size_t initialIndent; // indent of first line, or npos std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos std::size_t width; // maximum width of text, including indent. Longer text will wrap }; class Text { public: Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) : attr( _attr ) { const std::string wrappableBeforeChars = "[({<\t"; const std::string wrappableAfterChars = "])}>-,./|\\"; const std::string wrappableInsteadOfChars = " \n\r"; std::string indent = _attr.initialIndent != std::string::npos ? std::string( _attr.initialIndent, ' ' ) : std::string( _attr.indent, ' ' ); typedef std::string::const_iterator iterator; iterator it = _str.begin(); const iterator strEnd = _str.end(); while( it != strEnd ) { if( lines.size() >= 1000 ) { lines.push_back( "... message truncated due to excessive size" ); return; } std::string suffix; std::size_t width = (std::min)( static_cast( strEnd-it ), _attr.width-static_cast( indent.size() ) ); iterator itEnd = it+width; iterator itNext = _str.end(); iterator itNewLine = std::find( it, itEnd, '\n' ); if( itNewLine != itEnd ) itEnd = itNewLine; if( itEnd != strEnd ) { bool foundWrapPoint = false; iterator findIt = itEnd; do { if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) { itEnd = findIt+1; itNext = findIt+1; foundWrapPoint = true; } else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) { itEnd = findIt; itNext = findIt; foundWrapPoint = true; } else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) { itNext = findIt+1; itEnd = findIt; foundWrapPoint = true; } if( findIt == it ) break; else --findIt; } while( !foundWrapPoint ); if( !foundWrapPoint ) { // No good wrap char, so we'll break mid word and add a hyphen --itEnd; itNext = itEnd; suffix = "-"; } else { while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos ) --itEnd; } } lines.push_back( indent + std::string( it, itEnd ) + suffix ); if( indent.size() != _attr.indent ) indent = std::string( _attr.indent, ' ' ); it = itNext; } } typedef std::vector::const_iterator const_iterator; const_iterator begin() const { return lines.begin(); } const_iterator end() const { return lines.end(); } std::string const& last() const { return lines.back(); } std::size_t size() const { return lines.size(); } std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } std::string toString() const { std::ostringstream oss; oss << *this; return oss.str(); } inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); it != itEnd; ++it ) { if( it != _text.begin() ) _stream << "\n"; _stream << *it; } return _stream; } private: std::string str; TextAttributes attr; std::vector lines; }; } // end namespace Tbc #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE } // end outer namespace #endif #endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED #undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE namespace Catch { using Tbc::Text; using Tbc::TextAttributes; } // #included from: catch_console_colour.hpp #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED namespace Catch { struct Colour { enum Code { None = 0, White, Red, Green, Blue, Cyan, Yellow, Grey, Bright = 0x10, BrightRed = Bright | Red, BrightGreen = Bright | Green, LightGrey = Bright | Grey, BrightWhite = Bright | White, // By intention FileName = LightGrey, Warning = Yellow, ResultError = BrightRed, ResultSuccess = BrightGreen, ResultExpectedFailure = Warning, Error = BrightRed, Success = Green, OriginalExpression = Cyan, ReconstructedExpression = Yellow, SecondaryText = LightGrey, Headers = White }; // Use constructed object for RAII guard Colour( Code _colourCode ); Colour( Colour const& other ); ~Colour(); // Use static method for one-shot changes static void use( Code _colourCode ); private: bool m_moved; }; inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } } // end namespace Catch // #included from: catch_interfaces_reporter.h #define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED #include #include #include namespace Catch { struct ReporterConfig { explicit ReporterConfig( Ptr const& _fullConfig ) : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} std::ostream& stream() const { return *m_stream; } Ptr fullConfig() const { return m_fullConfig; } private: std::ostream* m_stream; Ptr m_fullConfig; }; struct ReporterPreferences { ReporterPreferences() : shouldRedirectStdOut( false ) {} bool shouldRedirectStdOut; }; template struct LazyStat : Option { LazyStat() : used( false ) {} LazyStat& operator=( T const& _value ) { Option::operator=( _value ); used = false; return *this; } void reset() { Option::reset(); used = false; } bool used; }; struct TestRunInfo { TestRunInfo( std::string const& _name ) : name( _name ) {} std::string name; }; struct GroupInfo { GroupInfo( std::string const& _name, std::size_t _groupIndex, std::size_t _groupsCount ) : name( _name ), groupIndex( _groupIndex ), groupsCounts( _groupsCount ) {} std::string name; std::size_t groupIndex; std::size_t groupsCounts; }; struct AssertionStats { AssertionStats( AssertionResult const& _assertionResult, std::vector const& _infoMessages, Totals const& _totals ) : assertionResult( _assertionResult ), infoMessages( _infoMessages ), totals( _totals ) { if( assertionResult.hasMessage() ) { // Copy message into messages list. // !TBD This should have been done earlier, somewhere MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); builder << assertionResult.getMessage(); builder.m_info.message = builder.m_stream.str(); infoMessages.push_back( builder.m_info ); } } virtual ~AssertionStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS AssertionStats( AssertionStats const& ) = default; AssertionStats( AssertionStats && ) = default; AssertionStats& operator = ( AssertionStats const& ) = default; AssertionStats& operator = ( AssertionStats && ) = default; # endif AssertionResult assertionResult; std::vector infoMessages; Totals totals; }; struct SectionStats { SectionStats( SectionInfo const& _sectionInfo, Counts const& _assertions, double _durationInSeconds, bool _missingAssertions ) : sectionInfo( _sectionInfo ), assertions( _assertions ), durationInSeconds( _durationInSeconds ), missingAssertions( _missingAssertions ) {} virtual ~SectionStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS SectionStats( SectionStats const& ) = default; SectionStats( SectionStats && ) = default; SectionStats& operator = ( SectionStats const& ) = default; SectionStats& operator = ( SectionStats && ) = default; # endif SectionInfo sectionInfo; Counts assertions; double durationInSeconds; bool missingAssertions; }; struct TestCaseStats { TestCaseStats( TestCaseInfo const& _testInfo, Totals const& _totals, std::string const& _stdOut, std::string const& _stdErr, bool _aborting ) : testInfo( _testInfo ), totals( _totals ), stdOut( _stdOut ), stdErr( _stdErr ), aborting( _aborting ) {} virtual ~TestCaseStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestCaseStats( TestCaseStats const& ) = default; TestCaseStats( TestCaseStats && ) = default; TestCaseStats& operator = ( TestCaseStats const& ) = default; TestCaseStats& operator = ( TestCaseStats && ) = default; # endif TestCaseInfo testInfo; Totals totals; std::string stdOut; std::string stdErr; bool aborting; }; struct TestGroupStats { TestGroupStats( GroupInfo const& _groupInfo, Totals const& _totals, bool _aborting ) : groupInfo( _groupInfo ), totals( _totals ), aborting( _aborting ) {} TestGroupStats( GroupInfo const& _groupInfo ) : groupInfo( _groupInfo ), aborting( false ) {} virtual ~TestGroupStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestGroupStats( TestGroupStats const& ) = default; TestGroupStats( TestGroupStats && ) = default; TestGroupStats& operator = ( TestGroupStats const& ) = default; TestGroupStats& operator = ( TestGroupStats && ) = default; # endif GroupInfo groupInfo; Totals totals; bool aborting; }; struct TestRunStats { TestRunStats( TestRunInfo const& _runInfo, Totals const& _totals, bool _aborting ) : runInfo( _runInfo ), totals( _totals ), aborting( _aborting ) {} virtual ~TestRunStats(); # ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS TestRunStats( TestRunStats const& _other ) : runInfo( _other.runInfo ), totals( _other.totals ), aborting( _other.aborting ) {} # else TestRunStats( TestRunStats const& ) = default; TestRunStats( TestRunStats && ) = default; TestRunStats& operator = ( TestRunStats const& ) = default; TestRunStats& operator = ( TestRunStats && ) = default; # endif TestRunInfo runInfo; Totals totals; bool aborting; }; class MultipleReporters; struct IStreamingReporter : IShared { virtual ~IStreamingReporter(); // Implementing class must also provide the following static method: // static std::string getDescription(); virtual ReporterPreferences getPreferences() const = 0; virtual void noMatchingTestCases( std::string const& spec ) = 0; virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; virtual void sectionEnded( SectionStats const& sectionStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; virtual void skipTest( TestCaseInfo const& testInfo ) = 0; virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; } }; struct IReporterFactory : IShared { virtual ~IReporterFactory(); virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; virtual std::string getDescription() const = 0; }; struct IReporterRegistry { typedef std::map > FactoryMap; typedef std::vector > Listeners; virtual ~IReporterRegistry(); virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; virtual FactoryMap const& getFactories() const = 0; virtual Listeners const& getListeners() const = 0; }; Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); } #include #include namespace Catch { inline std::size_t listTests( Config const& config ) { TestSpec testSpec = config.testSpec(); if( config.testSpec().hasFilters() ) Catch::cout() << "Matching test cases:\n"; else { Catch::cout() << "All available test cases:\n"; testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } std::size_t matchedTests = 0; TextAttributes nameAttr, descAttr, tagsAttr; nameAttr.setInitialIndent( 2 ).setIndent( 4 ); descAttr.setIndent( 4 ); tagsAttr.setIndent( 6 ); std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); Colour::Code colour = testCaseInfo.isHidden() ? Colour::SecondaryText : Colour::None; Colour colourGuard( colour ); Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; if( config.listExtraInfo() ) { Catch::cout() << " " << testCaseInfo.lineInfo << std::endl; std::string description = testCaseInfo.description; if( description.empty() ) description = "(NO DESCRIPTION)"; Catch::cout() << Text( description, descAttr ) << std::endl; } if( !testCaseInfo.tags.empty() ) Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; } if( !config.testSpec().hasFilters() ) Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl; else Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl; return matchedTests; } inline std::size_t listTestsNamesOnly( Config const& config ) { TestSpec testSpec = config.testSpec(); if( !config.testSpec().hasFilters() ) testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); std::size_t matchedTests = 0; std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); if( startsWith( testCaseInfo.name, '#' ) ) Catch::cout() << '"' << testCaseInfo.name << '"'; else Catch::cout() << testCaseInfo.name; if ( config.listExtraInfo() ) Catch::cout() << "\t@" << testCaseInfo.lineInfo; Catch::cout() << std::endl; } return matchedTests; } struct TagInfo { TagInfo() : count ( 0 ) {} void add( std::string const& spelling ) { ++count; spellings.insert( spelling ); } std::string all() const { std::string out; for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); it != itEnd; ++it ) out += "[" + *it + "]"; return out; } std::set spellings; std::size_t count; }; inline std::size_t listTags( Config const& config ) { TestSpec testSpec = config.testSpec(); if( config.testSpec().hasFilters() ) Catch::cout() << "Tags for matching test cases:\n"; else { Catch::cout() << "All available tags:\n"; testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } std::map tagCounts; std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), tagItEnd = it->getTestCaseInfo().tags.end(); tagIt != tagItEnd; ++tagIt ) { std::string tagName = *tagIt; std::string lcaseTagName = toLower( tagName ); std::map::iterator countIt = tagCounts.find( lcaseTagName ); if( countIt == tagCounts.end() ) countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; countIt->second.add( tagName ); } } for( std::map::const_iterator countIt = tagCounts.begin(), countItEnd = tagCounts.end(); countIt != countItEnd; ++countIt ) { std::ostringstream oss; oss << " " << std::setw(2) << countIt->second.count << " "; Text wrapper( countIt->second.all(), TextAttributes() .setInitialIndent( 0 ) .setIndent( oss.str().size() ) .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); Catch::cout() << oss.str() << wrapper << '\n'; } Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; return tagCounts.size(); } inline std::size_t listReporters( Config const& /*config*/ ) { Catch::cout() << "Available reporters:\n"; IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; std::size_t maxNameLen = 0; for(it = itBegin; it != itEnd; ++it ) maxNameLen = (std::max)( maxNameLen, it->first.size() ); for(it = itBegin; it != itEnd; ++it ) { Text wrapper( it->second->getDescription(), TextAttributes() .setInitialIndent( 0 ) .setIndent( 7+maxNameLen ) .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); Catch::cout() << " " << it->first << ':' << std::string( maxNameLen - it->first.size() + 2, ' ' ) << wrapper << '\n'; } Catch::cout() << std::endl; return factories.size(); } inline Option list( Config const& config ) { Option listedCount; if( config.listTests() || ( config.listExtraInfo() && !config.listTestNamesOnly() ) ) listedCount = listedCount.valueOr(0) + listTests( config ); if( config.listTestNamesOnly() ) listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); if( config.listTags() ) listedCount = listedCount.valueOr(0) + listTags( config ); if( config.listReporters() ) listedCount = listedCount.valueOr(0) + listReporters( config ); return listedCount; } } // end namespace Catch // #included from: internal/catch_run_context.hpp #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED // #included from: catch_test_case_tracker.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED #include #include #include #include #include CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS namespace Catch { namespace TestCaseTracking { struct NameAndLocation { std::string name; SourceLineInfo location; NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) : name( _name ), location( _location ) {} }; struct ITracker : SharedImpl<> { virtual ~ITracker(); // static queries virtual NameAndLocation const& nameAndLocation() const = 0; // dynamic queries virtual bool isComplete() const = 0; // Successfully completed or failed virtual bool isSuccessfullyCompleted() const = 0; virtual bool isOpen() const = 0; // Started but not complete virtual bool hasChildren() const = 0; virtual ITracker& parent() = 0; // actions virtual void close() = 0; // Successfully complete virtual void fail() = 0; virtual void markAsNeedingAnotherRun() = 0; virtual void addChild( Ptr const& child ) = 0; virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0; virtual void openChild() = 0; // Debug/ checking virtual bool isSectionTracker() const = 0; virtual bool isIndexTracker() const = 0; }; class TrackerContext { enum RunState { NotStarted, Executing, CompletedCycle }; Ptr m_rootTracker; ITracker* m_currentTracker; RunState m_runState; public: static TrackerContext& instance() { static TrackerContext s_instance; return s_instance; } TrackerContext() : m_currentTracker( CATCH_NULL ), m_runState( NotStarted ) {} ITracker& startRun(); void endRun() { m_rootTracker.reset(); m_currentTracker = CATCH_NULL; m_runState = NotStarted; } void startCycle() { m_currentTracker = m_rootTracker.get(); m_runState = Executing; } void completeCycle() { m_runState = CompletedCycle; } bool completedCycle() const { return m_runState == CompletedCycle; } ITracker& currentTracker() { return *m_currentTracker; } void setCurrentTracker( ITracker* tracker ) { m_currentTracker = tracker; } }; class TrackerBase : public ITracker { protected: enum CycleState { NotStarted, Executing, ExecutingChildren, NeedsAnotherRun, CompletedSuccessfully, Failed }; class TrackerHasName { NameAndLocation m_nameAndLocation; public: TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} bool operator ()( Ptr const& tracker ) { return tracker->nameAndLocation().name == m_nameAndLocation.name && tracker->nameAndLocation().location == m_nameAndLocation.location; } }; typedef std::vector > Children; NameAndLocation m_nameAndLocation; TrackerContext& m_ctx; ITracker* m_parent; Children m_children; CycleState m_runState; public: TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) : m_nameAndLocation( nameAndLocation ), m_ctx( ctx ), m_parent( parent ), m_runState( NotStarted ) {} virtual ~TrackerBase(); virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE { return m_nameAndLocation; } virtual bool isComplete() const CATCH_OVERRIDE { return m_runState == CompletedSuccessfully || m_runState == Failed; } virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { return m_runState == CompletedSuccessfully; } virtual bool isOpen() const CATCH_OVERRIDE { return m_runState != NotStarted && !isComplete(); } virtual bool hasChildren() const CATCH_OVERRIDE { return !m_children.empty(); } virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { m_children.push_back( child ); } virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE { Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); return( it != m_children.end() ) ? it->get() : CATCH_NULL; } virtual ITracker& parent() CATCH_OVERRIDE { assert( m_parent ); // Should always be non-null except for root return *m_parent; } virtual void openChild() CATCH_OVERRIDE { if( m_runState != ExecutingChildren ) { m_runState = ExecutingChildren; if( m_parent ) m_parent->openChild(); } } virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; } virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; } void open() { m_runState = Executing; moveToThis(); if( m_parent ) m_parent->openChild(); } virtual void close() CATCH_OVERRIDE { // Close any still open children (e.g. generators) while( &m_ctx.currentTracker() != this ) m_ctx.currentTracker().close(); switch( m_runState ) { case NotStarted: case CompletedSuccessfully: case Failed: throw std::logic_error( "Illogical state" ); case NeedsAnotherRun: break;; case Executing: m_runState = CompletedSuccessfully; break; case ExecutingChildren: if( m_children.empty() || m_children.back()->isComplete() ) m_runState = CompletedSuccessfully; break; default: throw std::logic_error( "Unexpected state" ); } moveToParent(); m_ctx.completeCycle(); } virtual void fail() CATCH_OVERRIDE { m_runState = Failed; if( m_parent ) m_parent->markAsNeedingAnotherRun(); moveToParent(); m_ctx.completeCycle(); } virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { m_runState = NeedsAnotherRun; } private: void moveToParent() { assert( m_parent ); m_ctx.setCurrentTracker( m_parent ); } void moveToThis() { m_ctx.setCurrentTracker( this ); } }; class SectionTracker : public TrackerBase { std::vector m_filters; public: SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) : TrackerBase( nameAndLocation, ctx, parent ) { if( parent ) { while( !parent->isSectionTracker() ) parent = &parent->parent(); SectionTracker& parentSection = static_cast( *parent ); addNextFilters( parentSection.m_filters ); } } virtual ~SectionTracker(); virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; } static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { SectionTracker* section = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); assert( childTracker->isSectionTracker() ); section = static_cast( childTracker ); } else { section = new SectionTracker( nameAndLocation, ctx, ¤tTracker ); currentTracker.addChild( section ); } if( !ctx.completedCycle() ) section->tryOpen(); return *section; } void tryOpen() { if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) open(); } void addInitialFilters( std::vector const& filters ) { if( !filters.empty() ) { m_filters.push_back(""); // Root - should never be consulted m_filters.push_back(""); // Test Case - not a section filter m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); } } void addNextFilters( std::vector const& filters ) { if( filters.size() > 1 ) m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); } }; class IndexTracker : public TrackerBase { int m_size; int m_index; public: IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) : TrackerBase( nameAndLocation, ctx, parent ), m_size( size ), m_index( -1 ) {} virtual ~IndexTracker(); virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; } static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { IndexTracker* tracker = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); assert( childTracker->isIndexTracker() ); tracker = static_cast( childTracker ); } else { tracker = new IndexTracker( nameAndLocation, ctx, ¤tTracker, size ); currentTracker.addChild( tracker ); } if( !ctx.completedCycle() && !tracker->isComplete() ) { if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) tracker->moveNext(); tracker->open(); } return *tracker; } int index() const { return m_index; } void moveNext() { m_index++; m_children.clear(); } virtual void close() CATCH_OVERRIDE { TrackerBase::close(); if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) m_runState = Executing; } }; inline ITracker& TrackerContext::startRun() { m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL ); m_currentTracker = CATCH_NULL; m_runState = Executing; return *m_rootTracker; } } // namespace TestCaseTracking using TestCaseTracking::ITracker; using TestCaseTracking::TrackerContext; using TestCaseTracking::SectionTracker; using TestCaseTracking::IndexTracker; } // namespace Catch CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS // #included from: catch_fatal_condition.hpp #define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED namespace Catch { // Report the error condition inline void reportFatal( std::string const& message ) { IContext& context = Catch::getCurrentContext(); IResultCapture* resultCapture = context.getResultCapture(); resultCapture->handleFatalErrorCondition( message ); } } // namespace Catch #if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// // #included from: catch_windows_h_proxy.h #define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED #ifdef CATCH_DEFINES_NOMINMAX # define NOMINMAX #endif #ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif #ifdef __AFXDLL #include #else #include #endif #ifdef CATCH_DEFINES_NOMINMAX # undef NOMINMAX #endif #ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN # undef WIN32_LEAN_AND_MEAN #endif # if !defined ( CATCH_CONFIG_WINDOWS_SEH ) namespace Catch { struct FatalConditionHandler { void reset() {} }; } # else // CATCH_CONFIG_WINDOWS_SEH is defined namespace Catch { struct SignalDefs { DWORD id; const char* name; }; extern SignalDefs signalDefs[]; // There is no 1-1 mapping between signals and windows exceptions. // Windows can easily distinguish between SO and SigSegV, // but SigInt, SigTerm, etc are handled differently. SignalDefs signalDefs[] = { { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, }; struct FatalConditionHandler { static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { reportFatal(signalDefs[i].name); } } // If its not an exception we care about, pass it along. // This stops us from eating debugger breaks etc. return EXCEPTION_CONTINUE_SEARCH; } FatalConditionHandler() { isSet = true; // 32k seems enough for Catch to handle stack overflow, // but the value was found experimentally, so there is no strong guarantee guaranteeSize = 32 * 1024; exceptionHandlerHandle = CATCH_NULL; // Register as first handler in current chain exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); // Pass in guarantee size to be filled SetThreadStackGuarantee(&guaranteeSize); } static void reset() { if (isSet) { // Unregister handler and restore the old guarantee RemoveVectoredExceptionHandler(exceptionHandlerHandle); SetThreadStackGuarantee(&guaranteeSize); exceptionHandlerHandle = CATCH_NULL; isSet = false; } } ~FatalConditionHandler() { reset(); } private: static bool isSet; static ULONG guaranteeSize; static PVOID exceptionHandlerHandle; }; bool FatalConditionHandler::isSet = false; ULONG FatalConditionHandler::guaranteeSize = 0; PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL; } // namespace Catch # endif // CATCH_CONFIG_WINDOWS_SEH #else // Not Windows - assumed to be POSIX compatible ////////////////////////// # if !defined(CATCH_CONFIG_POSIX_SIGNALS) namespace Catch { struct FatalConditionHandler { void reset() {} }; } # else // CATCH_CONFIG_POSIX_SIGNALS is defined #include namespace Catch { struct SignalDefs { int id; const char* name; }; extern SignalDefs signalDefs[]; SignalDefs signalDefs[] = { { SIGINT, "SIGINT - Terminal interrupt signal" }, { SIGILL, "SIGILL - Illegal instruction signal" }, { SIGFPE, "SIGFPE - Floating point error signal" }, { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, { SIGTERM, "SIGTERM - Termination request signal" }, { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } }; struct FatalConditionHandler { static bool isSet; static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)]; static stack_t oldSigStack; static char altStackMem[SIGSTKSZ]; static void handleSignal( int sig ) { std::string name = ""; for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { SignalDefs &def = signalDefs[i]; if (sig == def.id) { name = def.name; break; } } reset(); reportFatal(name); raise( sig ); } FatalConditionHandler() { isSet = true; stack_t sigStack; sigStack.ss_sp = altStackMem; sigStack.ss_size = SIGSTKSZ; sigStack.ss_flags = 0; sigaltstack(&sigStack, &oldSigStack); struct sigaction sa = { 0 }; sa.sa_handler = handleSignal; sa.sa_flags = SA_ONSTACK; for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); } } ~FatalConditionHandler() { reset(); } static void reset() { if( isSet ) { // Set signals back to previous values -- hopefully nobody overwrote them in the meantime for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL); } // Return the old stack sigaltstack(&oldSigStack, CATCH_NULL); isSet = false; } } }; bool FatalConditionHandler::isSet = false; struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; stack_t FatalConditionHandler::oldSigStack = {}; char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; } // namespace Catch # endif // CATCH_CONFIG_POSIX_SIGNALS #endif // not Windows #include #include namespace Catch { class StreamRedirect { public: StreamRedirect( std::ostream& stream, std::string& targetString ) : m_stream( stream ), m_prevBuf( stream.rdbuf() ), m_targetString( targetString ) { stream.rdbuf( m_oss.rdbuf() ); } ~StreamRedirect() { m_targetString += m_oss.str(); m_stream.rdbuf( m_prevBuf ); } private: std::ostream& m_stream; std::streambuf* m_prevBuf; std::ostringstream m_oss; std::string& m_targetString; }; // StdErr has two constituent streams in C++, std::cerr and std::clog // This means that we need to redirect 2 streams into 1 to keep proper // order of writes and cannot use StreamRedirect on its own class StdErrRedirect { public: StdErrRedirect(std::string& targetString) :m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()), m_targetString(targetString){ cerr().rdbuf(m_oss.rdbuf()); clog().rdbuf(m_oss.rdbuf()); } ~StdErrRedirect() { m_targetString += m_oss.str(); cerr().rdbuf(m_cerrBuf); clog().rdbuf(m_clogBuf); } private: std::streambuf* m_cerrBuf; std::streambuf* m_clogBuf; std::ostringstream m_oss; std::string& m_targetString; }; /////////////////////////////////////////////////////////////////////////// class RunContext : public IResultCapture, public IRunner { RunContext( RunContext const& ); void operator =( RunContext const& ); public: explicit RunContext( Ptr const& _config, Ptr const& reporter ) : m_runInfo( _config->name() ), m_context( getCurrentMutableContext() ), m_activeTestCase( CATCH_NULL ), m_config( _config ), m_reporter( reporter ), m_shouldReportUnexpected ( true ) { m_context.setRunner( this ); m_context.setConfig( m_config ); m_context.setResultCapture( this ); m_reporter->testRunStarting( m_runInfo ); } virtual ~RunContext() { m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); } void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); } void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); } Totals runTest( TestCase const& testCase ) { Totals prevTotals = m_totals; std::string redirectedCout; std::string redirectedCerr; TestCaseInfo testInfo = testCase.getTestCaseInfo(); m_reporter->testCaseStarting( testInfo ); m_activeTestCase = &testCase; do { ITracker& rootTracker = m_trackerContext.startRun(); assert( rootTracker.isSectionTracker() ); static_cast( rootTracker ).addInitialFilters( m_config->getSectionsToRun() ); do { m_trackerContext.startCycle(); m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) ); runCurrentTest( redirectedCout, redirectedCerr ); } while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); } // !TBD: deprecated - this will be replaced by indexed trackers while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); Totals deltaTotals = m_totals.delta( prevTotals ); if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) { deltaTotals.assertions.failed++; deltaTotals.testCases.passed--; deltaTotals.testCases.failed++; } m_totals.testCases += deltaTotals.testCases; m_reporter->testCaseEnded( TestCaseStats( testInfo, deltaTotals, redirectedCout, redirectedCerr, aborting() ) ); m_activeTestCase = CATCH_NULL; m_testCaseTracker = CATCH_NULL; return deltaTotals; } Ptr config() const { return m_config; } private: // IResultCapture virtual void assertionEnded( AssertionResult const& result ) { if( result.getResultType() == ResultWas::Ok ) { m_totals.assertions.passed++; } else if( !result.isOk() ) { m_totals.assertions.failed++; } // We have no use for the return value (whether messages should be cleared), because messages were made scoped // and should be let to clear themselves out. static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); // Reset working state m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); m_lastResult = result; } virtual bool lastAssertionPassed() { return m_totals.assertions.passed == (m_prevPassed + 1); } virtual void assertionPassed() { m_totals.assertions.passed++; m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"; m_lastAssertionInfo.macroName = ""; } virtual void assertionRun() { m_prevPassed = m_totals.assertions.passed; } virtual bool sectionStarted ( SectionInfo const& sectionInfo, Counts& assertions ) { ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) ); if( !sectionTracker.isOpen() ) return false; m_activeSections.push_back( §ionTracker ); m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; m_reporter->sectionStarting( sectionInfo ); assertions = m_totals.assertions; return true; } bool testForMissingAssertions( Counts& assertions ) { if( assertions.total() != 0 ) return false; if( !m_config->warnAboutMissingAssertions() ) return false; if( m_trackerContext.currentTracker().hasChildren() ) return false; m_totals.assertions.failed++; assertions.failed++; return true; } virtual void sectionEnded( SectionEndInfo const& endInfo ) { Counts assertions = m_totals.assertions - endInfo.prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); if( !m_activeSections.empty() ) { m_activeSections.back()->close(); m_activeSections.pop_back(); } m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); m_messages.clear(); } virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { if( m_unfinishedSections.empty() ) m_activeSections.back()->fail(); else m_activeSections.back()->close(); m_activeSections.pop_back(); m_unfinishedSections.push_back( endInfo ); } virtual void pushScopedMessage( MessageInfo const& message ) { m_messages.push_back( message ); } virtual void popScopedMessage( MessageInfo const& message ) { m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); } virtual std::string getCurrentTestName() const { return m_activeTestCase ? m_activeTestCase->getTestCaseInfo().name : std::string(); } virtual const AssertionResult* getLastResult() const { return &m_lastResult; } virtual void exceptionEarlyReported() { m_shouldReportUnexpected = false; } virtual void handleFatalErrorCondition( std::string const& message ) { // Don't rebuild the result -- the stringification itself can cause more fatal errors // Instead, fake a result data. AssertionResultData tempResult; tempResult.resultType = ResultWas::FatalErrorCondition; tempResult.message = message; AssertionResult result(m_lastAssertionInfo, tempResult); getResultCapture().assertionEnded(result); handleUnfinishedSections(); // Recreate section for test case (as we will lose the one that was in scope) TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); Counts assertions; assertions.failed = 1; SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); m_reporter->sectionEnded( testCaseSectionStats ); TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); Totals deltaTotals; deltaTotals.testCases.failed = 1; deltaTotals.assertions.failed = 1; m_reporter->testCaseEnded( TestCaseStats( testInfo, deltaTotals, std::string(), std::string(), false ) ); m_totals.testCases.failed++; testGroupEnded( std::string(), m_totals, 1, 1 ); m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); } public: // !TBD We need to do this another way! bool aborting() const { return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); } private: void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); m_reporter->sectionStarting( testCaseSection ); Counts prevAssertions = m_totals.assertions; double duration = 0; m_shouldReportUnexpected = true; try { m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); seedRng( *m_config ); Timer timer; timer.start(); if( m_reporter->getPreferences().shouldRedirectStdOut ) { StreamRedirect coutRedir( Catch::cout(), redirectedCout ); StdErrRedirect errRedir( redirectedCerr ); invokeActiveTestCase(); } else { invokeActiveTestCase(); } duration = timer.getElapsedSeconds(); } catch( TestFailureException& ) { // This just means the test was aborted due to failure } catch(...) { // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions // are reported without translation at the point of origin. if (m_shouldReportUnexpected) { makeUnexpectedResultBuilder().useActiveException(); } } m_testCaseTracker->close(); handleUnfinishedSections(); m_messages.clear(); Counts assertions = m_totals.assertions - prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); if( testCaseInfo.okToFail() ) { std::swap( assertions.failedButOk, assertions.failed ); m_totals.assertions.failed -= assertions.failedButOk; m_totals.assertions.failedButOk += assertions.failedButOk; } SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); m_reporter->sectionEnded( testCaseSectionStats ); } void invokeActiveTestCase() { FatalConditionHandler fatalConditionHandler; // Handle signals m_activeTestCase->invoke(); fatalConditionHandler.reset(); } private: ResultBuilder makeUnexpectedResultBuilder() const { return ResultBuilder( m_lastAssertionInfo.macroName, m_lastAssertionInfo.lineInfo, m_lastAssertionInfo.capturedExpression, m_lastAssertionInfo.resultDisposition ); } void handleUnfinishedSections() { // If sections ended prematurely due to an exception we stored their // infos here so we can tear them down outside the unwind process. for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), itEnd = m_unfinishedSections.rend(); it != itEnd; ++it ) sectionEnded( *it ); m_unfinishedSections.clear(); } TestRunInfo m_runInfo; IMutableContext& m_context; TestCase const* m_activeTestCase; ITracker* m_testCaseTracker; ITracker* m_currentSectionTracker; AssertionResult m_lastResult; Ptr m_config; Totals m_totals; Ptr m_reporter; std::vector m_messages; AssertionInfo m_lastAssertionInfo; std::vector m_unfinishedSections; std::vector m_activeSections; TrackerContext m_trackerContext; size_t m_prevPassed; bool m_shouldReportUnexpected; }; IResultCapture& getResultCapture() { if( IResultCapture* capture = getCurrentContext().getResultCapture() ) return *capture; else throw std::logic_error( "No result capture instance" ); } } // end namespace Catch // #included from: internal/catch_version.h #define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED namespace Catch { // Versioning information struct Version { Version( unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, char const * const _branchName, unsigned int _buildNumber ); unsigned int const majorVersion; unsigned int const minorVersion; unsigned int const patchNumber; // buildNumber is only used if branchName is not null char const * const branchName; unsigned int const buildNumber; friend std::ostream& operator << ( std::ostream& os, Version const& version ); private: void operator=( Version const& ); }; inline Version libraryVersion(); } #include #include #include namespace Catch { Ptr createReporter( std::string const& reporterName, Ptr const& config ) { Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); if( !reporter ) { std::ostringstream oss; oss << "No reporter registered with name: '" << reporterName << "'"; throw std::domain_error( oss.str() ); } return reporter; } #if !defined(CATCH_CONFIG_DEFAULT_REPORTER) #define CATCH_CONFIG_DEFAULT_REPORTER "console" #endif Ptr makeReporter( Ptr const& config ) { std::vector reporters = config->getReporterNames(); if( reporters.empty() ) reporters.push_back( CATCH_CONFIG_DEFAULT_REPORTER ); Ptr reporter; for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); it != itEnd; ++it ) reporter = addReporter( reporter, createReporter( *it, config ) ); return reporter; } Ptr addListeners( Ptr const& config, Ptr reporters ) { IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); it != itEnd; ++it ) reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); return reporters; } Totals runTests( Ptr const& config ) { Ptr iconfig = config.get(); Ptr reporter = makeReporter( config ); reporter = addListeners( iconfig, reporter ); RunContext context( iconfig, reporter ); Totals totals; context.testGroupStarting( config->name(), 1, 1 ); TestSpec testSpec = config->testSpec(); if( !testSpec.hasFilters() ) testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); it != itEnd; ++it ) { if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) totals += context.runTest( *it ); else reporter->skipTest( *it ); } context.testGroupEnded( iconfig->name(), totals, 1, 1 ); return totals; } void applyFilenamesAsTags( IConfig const& config ) { std::vector const& tests = getAllTestCasesSorted( config ); for(std::size_t i = 0; i < tests.size(); ++i ) { TestCase& test = const_cast( tests[i] ); std::set tags = test.tags; std::string filename = test.lineInfo.file; std::string::size_type lastSlash = filename.find_last_of( "\\/" ); if( lastSlash != std::string::npos ) filename = filename.substr( lastSlash+1 ); std::string::size_type lastDot = filename.find_last_of( '.' ); if( lastDot != std::string::npos ) filename = filename.substr( 0, lastDot ); tags.insert( '#' + filename ); setTags( test, tags ); } } class Session : NonCopyable { static bool alreadyInstantiated; public: struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; Session() : m_cli( makeCommandLineParser() ) { if( alreadyInstantiated ) { std::string msg = "Only one instance of Catch::Session can ever be used"; Catch::cerr() << msg << std::endl; throw std::logic_error( msg ); } alreadyInstantiated = true; } ~Session() { Catch::cleanUp(); } void showHelp( std::string const& processName ) { Catch::cout() << "\nCatch v" << libraryVersion() << "\n"; m_cli.usage( Catch::cout(), processName ); Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { try { m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); if( m_configData.showHelp ) showHelp( m_configData.processName ); m_config.reset(); } catch( std::exception& ex ) { { Colour colourGuard( Colour::Red ); Catch::cerr() << "\nError(s) in input:\n" << Text( ex.what(), TextAttributes().setIndent(2) ) << "\n\n"; } m_cli.usage( Catch::cout(), m_configData.processName ); return (std::numeric_limits::max)(); } return 0; } void useConfigData( ConfigData const& _configData ) { m_configData = _configData; m_config.reset(); } int run( int argc, char const* const* const argv ) { int returnCode = applyCommandLine( argc, argv ); if( returnCode == 0 ) returnCode = run(); return returnCode; } #if defined(WIN32) && defined(UNICODE) int run( int argc, wchar_t const* const* const argv ) { char **utf8Argv = new char *[ argc ]; for ( int i = 0; i < argc; ++i ) { int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); utf8Argv[ i ] = new char[ bufSize ]; WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); } int returnCode = applyCommandLine( argc, utf8Argv ); if( returnCode == 0 ) returnCode = run(); for ( int i = 0; i < argc; ++i ) delete [] utf8Argv[ i ]; delete [] utf8Argv; return returnCode; } #endif int run() { if( m_configData.showHelp ) return 0; try { config(); // Force config to be constructed seedRng( *m_config ); if( m_configData.filenamesAsTags ) applyFilenamesAsTags( *m_config ); // Handle list request if( Option listed = list( config() ) ) return static_cast( *listed ); return static_cast( runTests( m_config ).assertions.failed ); } catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; return (std::numeric_limits::max)(); } } Clara::CommandLine const& cli() const { return m_cli; } std::vector const& unusedTokens() const { return m_unusedTokens; } ConfigData& configData() { return m_configData; } Config& config() { if( !m_config ) m_config = new Config( m_configData ); return *m_config; } private: Clara::CommandLine m_cli; std::vector m_unusedTokens; ConfigData m_configData; Ptr m_config; }; bool Session::alreadyInstantiated = false; } // end namespace Catch // #included from: catch_registry_hub.hpp #define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED // #included from: catch_test_case_registry_impl.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED #include #include #include #include namespace Catch { struct RandomNumberGenerator { typedef std::ptrdiff_t result_type; result_type operator()( result_type n ) const { return std::rand() % n; } #ifdef CATCH_CONFIG_CPP11_SHUFFLE static constexpr result_type min() { return 0; } static constexpr result_type max() { return 1000000; } result_type operator()() const { return std::rand() % max(); } #endif template static void shuffle( V& vector ) { RandomNumberGenerator rng; #ifdef CATCH_CONFIG_CPP11_SHUFFLE std::shuffle( vector.begin(), vector.end(), rng ); #else std::random_shuffle( vector.begin(), vector.end(), rng ); #endif } }; inline std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { std::vector sorted = unsortedTestCases; switch( config.runOrder() ) { case RunTests::InLexicographicalOrder: std::sort( sorted.begin(), sorted.end() ); break; case RunTests::InRandomOrder: { seedRng( config ); RandomNumberGenerator::shuffle( sorted ); } break; case RunTests::InDeclarationOrder: // already in declaration order break; } return sorted; } bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); } void enforceNoDuplicateTestCases( std::vector const& functions ) { std::set seenFunctions; for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); it != itEnd; ++it ) { std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); if( !prev.second ) { std::ostringstream ss; ss << Colour( Colour::Red ) << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n' << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; throw std::runtime_error(ss.str()); } } } std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { std::vector filtered; filtered.reserve( testCases.size() ); for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); it != itEnd; ++it ) if( matchTest( *it, testSpec, config ) ) filtered.push_back( *it ); return filtered; } std::vector const& getAllTestCasesSorted( IConfig const& config ) { return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); } class TestRegistry : public ITestCaseRegistry { public: TestRegistry() : m_currentSortOrder( RunTests::InDeclarationOrder ), m_unnamedCount( 0 ) {} virtual ~TestRegistry(); virtual void registerTest( TestCase const& testCase ) { std::string name = testCase.getTestCaseInfo().name; if( name.empty() ) { std::ostringstream oss; oss << "Anonymous test case " << ++m_unnamedCount; return registerTest( testCase.withName( oss.str() ) ); } m_functions.push_back( testCase ); } virtual std::vector const& getAllTests() const { return m_functions; } virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { if( m_sortedFunctions.empty() ) enforceNoDuplicateTestCases( m_functions ); if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { m_sortedFunctions = sortTests( config, m_functions ); m_currentSortOrder = config.runOrder(); } return m_sortedFunctions; } private: std::vector m_functions; mutable RunTests::InWhatOrder m_currentSortOrder; mutable std::vector m_sortedFunctions; size_t m_unnamedCount; std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised }; /////////////////////////////////////////////////////////////////////////// class FreeFunctionTestCase : public SharedImpl { public: FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} virtual void invoke() const { m_fun(); } private: virtual ~FreeFunctionTestCase(); TestFunction m_fun; }; inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { std::string className = classOrQualifiedMethodName; if( startsWith( className, '&' ) ) { std::size_t lastColons = className.rfind( "::" ); std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); if( penultimateColons == std::string::npos ) penultimateColons = 1; className = className.substr( penultimateColons, lastColons-penultimateColons ); } return className; } void registerTestCase ( ITestCase* testCase, char const* classOrQualifiedMethodName, NameAndDesc const& nameAndDesc, SourceLineInfo const& lineInfo ) { getMutableRegistryHub().registerTest ( makeTestCase ( testCase, extractClassName( classOrQualifiedMethodName ), nameAndDesc.name, nameAndDesc.description, lineInfo ) ); } void registerTestCaseFunction ( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ) { registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); } /////////////////////////////////////////////////////////////////////////// AutoReg::AutoReg ( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ) { registerTestCaseFunction( function, lineInfo, nameAndDesc ); } AutoReg::~AutoReg() {} } // end namespace Catch // #included from: catch_reporter_registry.hpp #define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED #include namespace Catch { class ReporterRegistry : public IReporterRegistry { public: virtual ~ReporterRegistry() CATCH_OVERRIDE {} virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { FactoryMap::const_iterator it = m_factories.find( name ); if( it == m_factories.end() ) return CATCH_NULL; return it->second->create( ReporterConfig( config ) ); } void registerReporter( std::string const& name, Ptr const& factory ) { m_factories.insert( std::make_pair( name, factory ) ); } void registerListener( Ptr const& factory ) { m_listeners.push_back( factory ); } virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { return m_factories; } virtual Listeners const& getListeners() const CATCH_OVERRIDE { return m_listeners; } private: FactoryMap m_factories; Listeners m_listeners; }; } // #included from: catch_exception_translator_registry.hpp #define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED #ifdef __OBJC__ #import "Foundation/Foundation.h" #endif namespace Catch { class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { public: ~ExceptionTranslatorRegistry() { deleteAll( m_translators ); } virtual void registerTranslator( const IExceptionTranslator* translator ) { m_translators.push_back( translator ); } virtual std::string translateActiveException() const { try { #ifdef __OBJC__ // In Objective-C try objective-c exceptions first @try { return tryTranslators(); } @catch (NSException *exception) { return Catch::toString( [exception description] ); } #else return tryTranslators(); #endif } catch( TestFailureException& ) { throw; } catch( std::exception& ex ) { return ex.what(); } catch( std::string& msg ) { return msg; } catch( const char* msg ) { return msg; } catch(...) { return "Unknown exception"; } } std::string tryTranslators() const { if( m_translators.empty() ) throw; else return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); } private: std::vector m_translators; }; } // #included from: catch_tag_alias_registry.h #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED #include namespace Catch { class TagAliasRegistry : public ITagAliasRegistry { public: virtual ~TagAliasRegistry(); virtual Option find( std::string const& alias ) const; virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); private: std::map m_registry; }; } // end namespace Catch namespace Catch { namespace { class RegistryHub : public IRegistryHub, public IMutableRegistryHub { RegistryHub( RegistryHub const& ); void operator=( RegistryHub const& ); public: // IRegistryHub RegistryHub() { } virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { return m_reporterRegistry; } virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { return m_testCaseRegistry; } virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { return m_exceptionTranslatorRegistry; } virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE { return m_tagAliasRegistry; } public: // IMutableRegistryHub virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { m_reporterRegistry.registerReporter( name, factory ); } virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { m_reporterRegistry.registerListener( factory ); } virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { m_testCaseRegistry.registerTest( testInfo ); } virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { m_exceptionTranslatorRegistry.registerTranslator( translator ); } virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE { m_tagAliasRegistry.add( alias, tag, lineInfo ); } private: TestRegistry m_testCaseRegistry; ReporterRegistry m_reporterRegistry; ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; TagAliasRegistry m_tagAliasRegistry; }; // Single, global, instance inline RegistryHub*& getTheRegistryHub() { static RegistryHub* theRegistryHub = CATCH_NULL; if( !theRegistryHub ) theRegistryHub = new RegistryHub(); return theRegistryHub; } } IRegistryHub& getRegistryHub() { return *getTheRegistryHub(); } IMutableRegistryHub& getMutableRegistryHub() { return *getTheRegistryHub(); } void cleanUp() { delete getTheRegistryHub(); getTheRegistryHub() = CATCH_NULL; cleanUpContext(); } std::string translateActiveException() { return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); } } // end namespace Catch // #included from: catch_notimplemented_exception.hpp #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED #include namespace Catch { NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) : m_lineInfo( lineInfo ) { std::ostringstream oss; oss << lineInfo << ": function "; oss << "not implemented"; m_what = oss.str(); } const char* NotImplementedException::what() const CATCH_NOEXCEPT { return m_what.c_str(); } } // end namespace Catch // #included from: catch_context_impl.hpp #define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED // #included from: catch_stream.hpp #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED #include #include #include namespace Catch { template class StreamBufImpl : public StreamBufBase { char data[bufferSize]; WriterF m_writer; public: StreamBufImpl() { setp( data, data + sizeof(data) ); } ~StreamBufImpl() CATCH_NOEXCEPT { sync(); } private: int overflow( int c ) { sync(); if( c != EOF ) { if( pbase() == epptr() ) m_writer( std::string( 1, static_cast( c ) ) ); else sputc( static_cast( c ) ); } return 0; } int sync() { if( pbase() != pptr() ) { m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); setp( pbase(), epptr() ); } return 0; } }; /////////////////////////////////////////////////////////////////////////// FileStream::FileStream( std::string const& filename ) { m_ofs.open( filename.c_str() ); if( m_ofs.fail() ) { std::ostringstream oss; oss << "Unable to open file: '" << filename << '\''; throw std::domain_error( oss.str() ); } } std::ostream& FileStream::stream() const { return m_ofs; } struct OutputDebugWriter { void operator()( std::string const&str ) { writeToDebugConsole( str ); } }; DebugOutStream::DebugOutStream() : m_streamBuf( new StreamBufImpl() ), m_os( m_streamBuf.get() ) {} std::ostream& DebugOutStream::stream() const { return m_os; } // Store the streambuf from cout up-front because // cout may get redirected when running tests CoutStream::CoutStream() : m_os( Catch::cout().rdbuf() ) {} std::ostream& CoutStream::stream() const { return m_os; } #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions std::ostream& cout() { return std::cout; } std::ostream& cerr() { return std::cerr; } std::ostream& clog() { return std::clog; } #endif } namespace Catch { class Context : public IMutableContext { Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} Context( Context const& ); void operator=( Context const& ); public: virtual ~Context() { deleteAllValues( m_generatorsByTestName ); } public: // IContext virtual IResultCapture* getResultCapture() { return m_resultCapture; } virtual IRunner* getRunner() { return m_runner; } virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { return getGeneratorsForCurrentTest() .getGeneratorInfo( fileInfo, totalSize ) .getCurrentIndex(); } virtual bool advanceGeneratorsForCurrentTest() { IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); return generators && generators->moveNext(); } virtual Ptr getConfig() const { return m_config; } public: // IMutableContext virtual void setResultCapture( IResultCapture* resultCapture ) { m_resultCapture = resultCapture; } virtual void setRunner( IRunner* runner ) { m_runner = runner; } virtual void setConfig( Ptr const& config ) { m_config = config; } friend IMutableContext& getCurrentMutableContext(); private: IGeneratorsForTest* findGeneratorsForCurrentTest() { std::string testName = getResultCapture()->getCurrentTestName(); std::map::const_iterator it = m_generatorsByTestName.find( testName ); return it != m_generatorsByTestName.end() ? it->second : CATCH_NULL; } IGeneratorsForTest& getGeneratorsForCurrentTest() { IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); if( !generators ) { std::string testName = getResultCapture()->getCurrentTestName(); generators = createGeneratorsForTest(); m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); } return *generators; } private: Ptr m_config; IRunner* m_runner; IResultCapture* m_resultCapture; std::map m_generatorsByTestName; }; namespace { Context* currentContext = CATCH_NULL; } IMutableContext& getCurrentMutableContext() { if( !currentContext ) currentContext = new Context(); return *currentContext; } IContext& getCurrentContext() { return getCurrentMutableContext(); } void cleanUpContext() { delete currentContext; currentContext = CATCH_NULL; } } // #included from: catch_console_colour_impl.hpp #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED // #included from: catch_errno_guard.hpp #define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED #include namespace Catch { class ErrnoGuard { public: ErrnoGuard():m_oldErrno(errno){} ~ErrnoGuard() { errno = m_oldErrno; } private: int m_oldErrno; }; } namespace Catch { namespace { struct IColourImpl { virtual ~IColourImpl() {} virtual void use( Colour::Code _colourCode ) = 0; }; struct NoColourImpl : IColourImpl { void use( Colour::Code ) {} static IColourImpl* instance() { static NoColourImpl s_instance; return &s_instance; } }; } // anon namespace } // namespace Catch #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) # ifdef CATCH_PLATFORM_WINDOWS # define CATCH_CONFIG_COLOUR_WINDOWS # else # define CATCH_CONFIG_COLOUR_ANSI # endif #endif #if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// namespace Catch { namespace { class Win32ColourImpl : public IColourImpl { public: Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) { CONSOLE_SCREEN_BUFFER_INFO csbiInfo; GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); } virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { case Colour::None: return setTextAttribute( originalForegroundAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Red: return setTextAttribute( FOREGROUND_RED ); case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); case Colour::Grey: return setTextAttribute( 0 ); case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Bright: throw std::logic_error( "not a colour" ); } } private: void setTextAttribute( WORD _textAttribute ) { SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); } HANDLE stdoutHandle; WORD originalForegroundAttributes; WORD originalBackgroundAttributes; }; IColourImpl* platformColourInstance() { static Win32ColourImpl s_instance; Ptr config = getCurrentContext().getConfig(); UseColour::YesOrNo colourMode = config ? config->useColour() : UseColour::Auto; if( colourMode == UseColour::Auto ) colourMode = !isDebuggerActive() ? UseColour::Yes : UseColour::No; return colourMode == UseColour::Yes ? &s_instance : NoColourImpl::instance(); } } // end anon namespace } // end namespace Catch #elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// #include namespace Catch { namespace { // use POSIX/ ANSI console terminal codes // Thanks to Adam Strzelecki for original contribution // (http://github.com/nanoant) // https://github.com/philsquared/Catch/pull/131 class PosixColourImpl : public IColourImpl { public: virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { case Colour::None: case Colour::White: return setColour( "[0m" ); case Colour::Red: return setColour( "[0;31m" ); case Colour::Green: return setColour( "[0;32m" ); case Colour::Blue: return setColour( "[0;34m" ); case Colour::Cyan: return setColour( "[0;36m" ); case Colour::Yellow: return setColour( "[0;33m" ); case Colour::Grey: return setColour( "[1;30m" ); case Colour::LightGrey: return setColour( "[0;37m" ); case Colour::BrightRed: return setColour( "[1;31m" ); case Colour::BrightGreen: return setColour( "[1;32m" ); case Colour::BrightWhite: return setColour( "[1;37m" ); case Colour::Bright: throw std::logic_error( "not a colour" ); } } static IColourImpl* instance() { static PosixColourImpl s_instance; return &s_instance; } private: void setColour( const char* _escapeCode ) { Catch::cout() << '\033' << _escapeCode; } }; IColourImpl* platformColourInstance() { ErrnoGuard guard; Ptr config = getCurrentContext().getConfig(); UseColour::YesOrNo colourMode = config ? config->useColour() : UseColour::Auto; if( colourMode == UseColour::Auto ) colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) ? UseColour::Yes : UseColour::No; return colourMode == UseColour::Yes ? PosixColourImpl::instance() : NoColourImpl::instance(); } } // end anon namespace } // end namespace Catch #else // not Windows or ANSI /////////////////////////////////////////////// namespace Catch { static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } } // end namespace Catch #endif // Windows/ ANSI/ None namespace Catch { Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } Colour::~Colour(){ if( !m_moved ) use( None ); } void Colour::use( Code _colourCode ) { static IColourImpl* impl = platformColourInstance(); impl->use( _colourCode ); } } // end namespace Catch // #included from: catch_generators_impl.hpp #define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED #include #include #include namespace Catch { struct GeneratorInfo : IGeneratorInfo { GeneratorInfo( std::size_t size ) : m_size( size ), m_currentIndex( 0 ) {} bool moveNext() { if( ++m_currentIndex == m_size ) { m_currentIndex = 0; return false; } return true; } std::size_t getCurrentIndex() const { return m_currentIndex; } std::size_t m_size; std::size_t m_currentIndex; }; /////////////////////////////////////////////////////////////////////////// class GeneratorsForTest : public IGeneratorsForTest { public: ~GeneratorsForTest() { deleteAll( m_generatorsInOrder ); } IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { std::map::const_iterator it = m_generatorsByName.find( fileInfo ); if( it == m_generatorsByName.end() ) { IGeneratorInfo* info = new GeneratorInfo( size ); m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); m_generatorsInOrder.push_back( info ); return *info; } return *it->second; } bool moveNext() { std::vector::const_iterator it = m_generatorsInOrder.begin(); std::vector::const_iterator itEnd = m_generatorsInOrder.end(); for(; it != itEnd; ++it ) { if( (*it)->moveNext() ) return true; } return false; } private: std::map m_generatorsByName; std::vector m_generatorsInOrder; }; IGeneratorsForTest* createGeneratorsForTest() { return new GeneratorsForTest(); } } // end namespace Catch // #included from: catch_assertionresult.hpp #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED namespace Catch { AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Normal), secondArg(""){} AssertionInfo::AssertionInfo( char const * _macroName, SourceLineInfo const& _lineInfo, char const * _capturedExpression, ResultDisposition::Flags _resultDisposition, char const * _secondArg) : macroName( _macroName ), lineInfo( _lineInfo ), capturedExpression( _capturedExpression ), resultDisposition( _resultDisposition ), secondArg( _secondArg ) {} AssertionResult::AssertionResult() {} AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) : m_info( info ), m_resultData( data ) {} AssertionResult::~AssertionResult() {} // Result was a success bool AssertionResult::succeeded() const { return Catch::isOk( m_resultData.resultType ); } // Result was a success, or failure is suppressed bool AssertionResult::isOk() const { return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); } ResultWas::OfType AssertionResult::getResultType() const { return m_resultData.resultType; } bool AssertionResult::hasExpression() const { return m_info.capturedExpression[0] != 0; } bool AssertionResult::hasMessage() const { return !m_resultData.message.empty(); } std::string capturedExpressionWithSecondArgument( char const * capturedExpression, char const * secondArg ) { return (secondArg[0] == 0 || secondArg[0] == '"' && secondArg[1] == '"') ? capturedExpression : std::string(capturedExpression) + ", " + secondArg; } std::string AssertionResult::getExpression() const { if( isFalseTest( m_info.resultDisposition ) ) return '!' + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); else return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); } std::string AssertionResult::getExpressionInMacro() const { if( m_info.macroName[0] == 0 ) return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); else return std::string(m_info.macroName) + "( " + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + " )"; } bool AssertionResult::hasExpandedExpression() const { return hasExpression() && getExpandedExpression() != getExpression(); } std::string AssertionResult::getExpandedExpression() const { return m_resultData.reconstructExpression(); } std::string AssertionResult::getMessage() const { return m_resultData.message; } SourceLineInfo AssertionResult::getSourceInfo() const { return m_info.lineInfo; } std::string AssertionResult::getTestMacroName() const { return m_info.macroName; } void AssertionResult::discardDecomposedExpression() const { m_resultData.decomposedExpression = CATCH_NULL; } void AssertionResult::expandDecomposedExpression() const { m_resultData.reconstructExpression(); } } // end namespace Catch // #included from: catch_test_case_info.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED #include namespace Catch { inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { if( startsWith( tag, '.' ) || tag == "hide" || tag == "!hide" ) return TestCaseInfo::IsHidden; else if( tag == "!throws" ) return TestCaseInfo::Throws; else if( tag == "!shouldfail" ) return TestCaseInfo::ShouldFail; else if( tag == "!mayfail" ) return TestCaseInfo::MayFail; else if( tag == "!nonportable" ) return TestCaseInfo::NonPortable; else return TestCaseInfo::None; } inline bool isReservedTag( std::string const& tag ) { return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] ); } inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { if( isReservedTag( tag ) ) { std::ostringstream ss; ss << Colour(Colour::Red) << "Tag name [" << tag << "] not allowed.\n" << "Tag names starting with non alpha-numeric characters are reserved\n" << Colour(Colour::FileName) << _lineInfo << '\n'; throw std::runtime_error(ss.str()); } } TestCase makeTestCase( ITestCase* _testCase, std::string const& _className, std::string const& _name, std::string const& _descOrTags, SourceLineInfo const& _lineInfo ) { bool isHidden( startsWith( _name, "./" ) ); // Legacy support // Parse out tags std::set tags; std::string desc, tag; bool inTag = false; for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { char c = _descOrTags[i]; if( !inTag ) { if( c == '[' ) inTag = true; else desc += c; } else { if( c == ']' ) { TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); if( prop == TestCaseInfo::IsHidden ) isHidden = true; else if( prop == TestCaseInfo::None ) enforceNotReservedTag( tag, _lineInfo ); tags.insert( tag ); tag.clear(); inTag = false; } else tag += c; } } if( isHidden ) { tags.insert( "hide" ); tags.insert( "." ); } TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); return TestCase( _testCase, info ); } void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) { testCaseInfo.tags = tags; testCaseInfo.lcaseTags.clear(); std::ostringstream oss; for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { oss << '[' << *it << ']'; std::string lcaseTag = toLower( *it ); testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); testCaseInfo.lcaseTags.insert( lcaseTag ); } testCaseInfo.tagsAsString = oss.str(); } TestCaseInfo::TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, std::set const& _tags, SourceLineInfo const& _lineInfo ) : name( _name ), className( _className ), description( _description ), lineInfo( _lineInfo ), properties( None ) { setTags( *this, _tags ); } TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) : name( other.name ), className( other.className ), description( other.description ), tags( other.tags ), lcaseTags( other.lcaseTags ), tagsAsString( other.tagsAsString ), lineInfo( other.lineInfo ), properties( other.properties ) {} bool TestCaseInfo::isHidden() const { return ( properties & IsHidden ) != 0; } bool TestCaseInfo::throws() const { return ( properties & Throws ) != 0; } bool TestCaseInfo::okToFail() const { return ( properties & (ShouldFail | MayFail ) ) != 0; } bool TestCaseInfo::expectedToFail() const { return ( properties & (ShouldFail ) ) != 0; } TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} TestCase::TestCase( TestCase const& other ) : TestCaseInfo( other ), test( other.test ) {} TestCase TestCase::withName( std::string const& _newName ) const { TestCase other( *this ); other.name = _newName; return other; } void TestCase::swap( TestCase& other ) { test.swap( other.test ); name.swap( other.name ); className.swap( other.className ); description.swap( other.description ); tags.swap( other.tags ); lcaseTags.swap( other.lcaseTags ); tagsAsString.swap( other.tagsAsString ); std::swap( TestCaseInfo::properties, static_cast( other ).properties ); std::swap( lineInfo, other.lineInfo ); } void TestCase::invoke() const { test->invoke(); } bool TestCase::operator == ( TestCase const& other ) const { return test.get() == other.test.get() && name == other.name && className == other.className; } bool TestCase::operator < ( TestCase const& other ) const { return name < other.name; } TestCase& TestCase::operator = ( TestCase const& other ) { TestCase temp( other ); swap( temp ); return *this; } TestCaseInfo const& TestCase::getTestCaseInfo() const { return *this; } } // end namespace Catch // #included from: catch_version.hpp #define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED namespace Catch { Version::Version ( unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, char const * const _branchName, unsigned int _buildNumber ) : majorVersion( _majorVersion ), minorVersion( _minorVersion ), patchNumber( _patchNumber ), branchName( _branchName ), buildNumber( _buildNumber ) {} std::ostream& operator << ( std::ostream& os, Version const& version ) { os << version.majorVersion << '.' << version.minorVersion << '.' << version.patchNumber; // branchName is never null -> 0th char is \0 if it is empty if (version.branchName[0]) { os << '-' << version.branchName << '.' << version.buildNumber; } return os; } inline Version libraryVersion() { static Version version( 1, 9, 7, "", 0 ); return version; } } // #included from: catch_message.hpp #define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED namespace Catch { MessageInfo::MessageInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ) : macroName( _macroName ), lineInfo( _lineInfo ), type( _type ), sequence( ++globalCount ) {} // This may need protecting if threading support is added unsigned int MessageInfo::globalCount = 0; //////////////////////////////////////////////////////////////////////////// ScopedMessage::ScopedMessage( MessageBuilder const& builder ) : m_info( builder.m_info ) { m_info.message = builder.m_stream.str(); getResultCapture().pushScopedMessage( m_info ); } ScopedMessage::ScopedMessage( ScopedMessage const& other ) : m_info( other.m_info ) {} ScopedMessage::~ScopedMessage() { if ( !std::uncaught_exception() ){ getResultCapture().popScopedMessage(m_info); } } } // end namespace Catch // #included from: catch_legacy_reporter_adapter.hpp #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED // #included from: catch_legacy_reporter_adapter.h #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED namespace Catch { // Deprecated struct IReporter : IShared { virtual ~IReporter(); virtual bool shouldRedirectStdout() const = 0; virtual void StartTesting() = 0; virtual void EndTesting( Totals const& totals ) = 0; virtual void StartGroup( std::string const& groupName ) = 0; virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; virtual void Aborted() = 0; virtual void Result( AssertionResult const& result ) = 0; }; class LegacyReporterAdapter : public SharedImpl { public: LegacyReporterAdapter( Ptr const& legacyReporter ); virtual ~LegacyReporterAdapter(); virtual ReporterPreferences getPreferences() const; virtual void noMatchingTestCases( std::string const& ); virtual void testRunStarting( TestRunInfo const& ); virtual void testGroupStarting( GroupInfo const& groupInfo ); virtual void testCaseStarting( TestCaseInfo const& testInfo ); virtual void sectionStarting( SectionInfo const& sectionInfo ); virtual void assertionStarting( AssertionInfo const& ); virtual bool assertionEnded( AssertionStats const& assertionStats ); virtual void sectionEnded( SectionStats const& sectionStats ); virtual void testCaseEnded( TestCaseStats const& testCaseStats ); virtual void testGroupEnded( TestGroupStats const& testGroupStats ); virtual void testRunEnded( TestRunStats const& testRunStats ); virtual void skipTest( TestCaseInfo const& ); private: Ptr m_legacyReporter; }; } namespace Catch { LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) : m_legacyReporter( legacyReporter ) {} LegacyReporterAdapter::~LegacyReporterAdapter() {} ReporterPreferences LegacyReporterAdapter::getPreferences() const { ReporterPreferences prefs; prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); return prefs; } void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { m_legacyReporter->StartTesting(); } void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { m_legacyReporter->StartGroup( groupInfo.name ); } void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { m_legacyReporter->StartTestCase( testInfo ); } void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); } void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { // Not on legacy interface } bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); it != itEnd; ++it ) { if( it->type == ResultWas::Info ) { ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); rb << it->message; rb.setResultType( ResultWas::Info ); AssertionResult result = rb.build(); m_legacyReporter->Result( result ); } } } m_legacyReporter->Result( assertionStats.assertionResult ); return true; } void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { if( sectionStats.missingAssertions ) m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); } void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { m_legacyReporter->EndTestCase ( testCaseStats.testInfo, testCaseStats.totals, testCaseStats.stdOut, testCaseStats.stdErr ); } void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { if( testGroupStats.aborting ) m_legacyReporter->Aborted(); m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); } void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { m_legacyReporter->EndTesting( testRunStats.totals ); } void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { } } // #included from: catch_timer.hpp #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wc++11-long-long" #endif #ifdef CATCH_PLATFORM_WINDOWS #else #include #endif namespace Catch { namespace { #ifdef CATCH_PLATFORM_WINDOWS UInt64 getCurrentTicks() { static UInt64 hz=0, hzo=0; if (!hz) { QueryPerformanceFrequency( reinterpret_cast( &hz ) ); QueryPerformanceCounter( reinterpret_cast( &hzo ) ); } UInt64 t; QueryPerformanceCounter( reinterpret_cast( &t ) ); return ((t-hzo)*1000000)/hz; } #else UInt64 getCurrentTicks() { timeval t; gettimeofday(&t,CATCH_NULL); return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); } #endif } void Timer::start() { m_ticks = getCurrentTicks(); } unsigned int Timer::getElapsedMicroseconds() const { return static_cast(getCurrentTicks() - m_ticks); } unsigned int Timer::getElapsedMilliseconds() const { return static_cast(getElapsedMicroseconds()/1000); } double Timer::getElapsedSeconds() const { return getElapsedMicroseconds()/1000000.0; } } // namespace Catch #ifdef __clang__ #pragma clang diagnostic pop #endif // #included from: catch_common.hpp #define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED #include #include namespace Catch { bool startsWith( std::string const& s, std::string const& prefix ) { return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); } bool startsWith( std::string const& s, char prefix ) { return !s.empty() && s[0] == prefix; } bool endsWith( std::string const& s, std::string const& suffix ) { return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); } bool endsWith( std::string const& s, char suffix ) { return !s.empty() && s[s.size()-1] == suffix; } bool contains( std::string const& s, std::string const& infix ) { return s.find( infix ) != std::string::npos; } char toLowerCh(char c) { return static_cast( std::tolower( c ) ); } void toLowerInPlace( std::string& s ) { std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); } std::string toLower( std::string const& s ) { std::string lc = s; toLowerInPlace( lc ); return lc; } std::string trim( std::string const& str ) { static char const* whitespaceChars = "\n\r\t "; std::string::size_type start = str.find_first_not_of( whitespaceChars ); std::string::size_type end = str.find_last_not_of( whitespaceChars ); return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); } bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { bool replaced = false; std::size_t i = str.find( replaceThis ); while( i != std::string::npos ) { replaced = true; str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); if( i < str.size()-withThis.size() ) i = str.find( replaceThis, i+withThis.size() ); else i = std::string::npos; } return replaced; } pluralise::pluralise( std::size_t count, std::string const& label ) : m_count( count ), m_label( label ) {} std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { os << pluraliser.m_count << ' ' << pluraliser.m_label; if( pluraliser.m_count != 1 ) os << 's'; return os; } SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){} SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) : file( _file ), line( _line ) {} bool SourceLineInfo::empty() const { return file[0] == '\0'; } bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); } bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); } void seedRng( IConfig const& config ) { if( config.rngSeed() != 0 ) std::srand( config.rngSeed() ); } unsigned int rngSeed() { return getCurrentContext().getConfig()->rngSeed(); } std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { #ifndef __GNUG__ os << info.file << '(' << info.line << ')'; #else os << info.file << ':' << info.line; #endif return os; } void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { std::ostringstream oss; oss << locationInfo << ": Internal Catch error: '" << message << '\''; if( alwaysTrue() ) throw std::logic_error( oss.str() ); } } // #included from: catch_section.hpp #define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED namespace Catch { SectionInfo::SectionInfo ( SourceLineInfo const& _lineInfo, std::string const& _name, std::string const& _description ) : name( _name ), description( _description ), lineInfo( _lineInfo ) {} Section::Section( SectionInfo const& info ) : m_info( info ), m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) { m_timer.start(); } #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17 #endif Section::~Section() { if( m_sectionIncluded ) { SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); if( std::uncaught_exception() ) getResultCapture().sectionEndedEarly( endInfo ); else getResultCapture().sectionEnded( endInfo ); } } #if defined(_MSC_VER) #pragma warning(pop) #endif // This indicates whether the section should be executed or not Section::operator bool() const { return m_sectionIncluded; } } // end namespace Catch // #included from: catch_debugger.hpp #define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED #ifdef CATCH_PLATFORM_MAC #include #include #include #include #include namespace Catch{ // The following function is taken directly from the following technical note: // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html // Returns true if the current process is being debugged (either // running under the debugger or has a debugger attached post facto). bool isDebuggerActive(){ int mib[4]; struct kinfo_proc info; size_t size; // Initialize the flags so that, if sysctl fails for some bizarre // reason, we get a predictable result. info.kp_proc.p_flag = 0; // Initialize mib, which tells sysctl the info we want, in this case // we're looking for information about a specific process ID. mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = getpid(); // Call sysctl. size = sizeof(info); if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; return false; } // We're being debugged if the P_TRACED flag is set. return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); } } // namespace Catch #elif defined(CATCH_PLATFORM_LINUX) #include #include namespace Catch{ // The standard POSIX way of detecting a debugger is to attempt to // ptrace() the process, but this needs to be done from a child and not // this process itself to still allow attaching to this process later // if wanted, so is rather heavy. Under Linux we have the PID of the // "debugger" (which doesn't need to be gdb, of course, it could also // be strace, for example) in /proc/$PID/status, so just get it from // there instead. bool isDebuggerActive(){ // Libstdc++ has a bug, where std::ifstream sets errno to 0 // This way our users can properly assert over errno values ErrnoGuard guard; std::ifstream in("/proc/self/status"); for( std::string line; std::getline(in, line); ) { static const int PREFIX_LEN = 11; if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { // We're traced if the PID is not 0 and no other PID starts // with 0 digit, so it's enough to check for just a single // character. return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; } } return false; } } // namespace Catch #elif defined(_MSC_VER) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace Catch { bool isDebuggerActive() { return IsDebuggerPresent() != 0; } } #elif defined(__MINGW32__) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace Catch { bool isDebuggerActive() { return IsDebuggerPresent() != 0; } } #else namespace Catch { inline bool isDebuggerActive() { return false; } } #endif // Platform #ifdef CATCH_PLATFORM_WINDOWS namespace Catch { void writeToDebugConsole( std::string const& text ) { ::OutputDebugStringA( text.c_str() ); } } #else namespace Catch { void writeToDebugConsole( std::string const& text ) { // !TBD: Need a version for Mac/ XCode and other IDEs Catch::cout() << text; } } #endif // Platform // #included from: catch_tostring.hpp #define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED namespace Catch { namespace Detail { const std::string unprintableString = "{?}"; namespace { const int hexThreshold = 255; struct Endianness { enum Arch { Big, Little }; static Arch which() { union _{ int asInt; char asChar[sizeof (int)]; } u; u.asInt = 1; return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; } }; } std::string rawMemoryToString( const void *object, std::size_t size ) { // Reverse order for little endian architectures int i = 0, end = static_cast( size ), inc = 1; if( Endianness::which() == Endianness::Little ) { i = end-1; end = inc = -1; } unsigned char const *bytes = static_cast(object); std::ostringstream os; os << "0x" << std::setfill('0') << std::hex; for( ; i != end; i += inc ) os << std::setw(2) << static_cast(bytes[i]); return os.str(); } } std::string toString( std::string const& value ) { std::string s = value; if( getCurrentContext().getConfig()->showInvisibles() ) { for(size_t i = 0; i < s.size(); ++i ) { std::string subs; switch( s[i] ) { case '\n': subs = "\\n"; break; case '\t': subs = "\\t"; break; default: break; } if( !subs.empty() ) { s = s.substr( 0, i ) + subs + s.substr( i+1 ); ++i; } } } return '"' + s + '"'; } std::string toString( std::wstring const& value ) { std::string s; s.reserve( value.size() ); for(size_t i = 0; i < value.size(); ++i ) s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; return Catch::toString( s ); } std::string toString( const char* const value ) { return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); } std::string toString( char* const value ) { return Catch::toString( static_cast( value ) ); } std::string toString( const wchar_t* const value ) { return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); } std::string toString( wchar_t* const value ) { return Catch::toString( static_cast( value ) ); } std::string toString( int value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ')'; return oss.str(); } std::string toString( unsigned long value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ')'; return oss.str(); } std::string toString( unsigned int value ) { return Catch::toString( static_cast( value ) ); } template std::string fpToString( T value, int precision ) { std::ostringstream oss; oss << std::setprecision( precision ) << std::fixed << value; std::string d = oss.str(); std::size_t i = d.find_last_not_of( '0' ); if( i != std::string::npos && i != d.size()-1 ) { if( d[i] == '.' ) i++; d = d.substr( 0, i+1 ); } return d; } std::string toString( const double value ) { return fpToString( value, 10 ); } std::string toString( const float value ) { return fpToString( value, 5 ) + 'f'; } std::string toString( bool value ) { return value ? "true" : "false"; } std::string toString( char value ) { if ( value == '\r' ) return "'\\r'"; if ( value == '\f' ) return "'\\f'"; if ( value == '\n' ) return "'\\n'"; if ( value == '\t' ) return "'\\t'"; if ( '\0' <= value && value < ' ' ) return toString( static_cast( value ) ); char chstr[] = "' '"; chstr[1] = value; return chstr; } std::string toString( signed char value ) { return toString( static_cast( value ) ); } std::string toString( unsigned char value ) { return toString( static_cast( value ) ); } #ifdef CATCH_CONFIG_CPP11_LONG_LONG std::string toString( long long value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ')'; return oss.str(); } std::string toString( unsigned long long value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ')'; return oss.str(); } #endif #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ) { return "nullptr"; } #endif #ifdef __OBJC__ std::string toString( NSString const * const& nsstring ) { if( !nsstring ) return "nil"; return "@" + toString([nsstring UTF8String]); } std::string toString( NSString * CATCH_ARC_STRONG & nsstring ) { if( !nsstring ) return "nil"; return "@" + toString([nsstring UTF8String]); } std::string toString( NSObject* const& nsObject ) { return toString( [nsObject description] ); } #endif } // end namespace Catch // #included from: catch_result_builder.hpp #define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED namespace Catch { ResultBuilder::ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, ResultDisposition::Flags resultDisposition, char const* secondArg ) : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ), m_shouldDebugBreak( false ), m_shouldThrow( false ), m_guardException( false ), m_usedStream( false ) {} ResultBuilder::~ResultBuilder() { #if defined(CATCH_CONFIG_FAST_COMPILE) if ( m_guardException ) { stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; captureResult( ResultWas::ThrewException ); getCurrentContext().getResultCapture()->exceptionEarlyReported(); } #endif } ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { m_data.resultType = result; return *this; } ResultBuilder& ResultBuilder::setResultType( bool result ) { m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; return *this; } void ResultBuilder::endExpression( DecomposedExpression const& expr ) { // Flip bool results if FalseTest flag is set if( isFalseTest( m_assertionInfo.resultDisposition ) ) { m_data.negate( expr.isBinaryExpression() ); } getResultCapture().assertionRun(); if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok) { AssertionResult result = build( expr ); handleResult( result ); } else getResultCapture().assertionPassed(); } void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { m_assertionInfo.resultDisposition = resultDisposition; stream().oss << Catch::translateActiveException(); captureResult( ResultWas::ThrewException ); } void ResultBuilder::captureResult( ResultWas::OfType resultType ) { setResultType( resultType ); captureExpression(); } void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { if( expectedMessage.empty() ) captureExpectedException( Matchers::Impl::MatchAllOf() ); else captureExpectedException( Matchers::Equals( expectedMessage ) ); } void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase const& matcher ) { assert( !isFalseTest( m_assertionInfo.resultDisposition ) ); AssertionResultData data = m_data; data.resultType = ResultWas::Ok; data.reconstructedExpression = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg); std::string actualMessage = Catch::translateActiveException(); if( !matcher.match( actualMessage ) ) { data.resultType = ResultWas::ExpressionFailed; data.reconstructedExpression = actualMessage; } AssertionResult result( m_assertionInfo, data ); handleResult( result ); } void ResultBuilder::captureExpression() { AssertionResult result = build(); handleResult( result ); } void ResultBuilder::handleResult( AssertionResult const& result ) { getResultCapture().assertionEnded( result ); if( !result.isOk() ) { if( getCurrentContext().getConfig()->shouldDebugBreak() ) m_shouldDebugBreak = true; if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) m_shouldThrow = true; } } void ResultBuilder::react() { #if defined(CATCH_CONFIG_FAST_COMPILE) if (m_shouldDebugBreak) { /////////////////////////////////////////////////////////////////// // To inspect the state during test, you need to go one level up the callstack // To go back to the test and change execution, jump over the throw statement /////////////////////////////////////////////////////////////////// CATCH_BREAK_INTO_DEBUGGER(); } #endif if( m_shouldThrow ) throw Catch::TestFailureException(); } bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } AssertionResult ResultBuilder::build() const { return build( *this ); } // CAVEAT: The returned AssertionResult stores a pointer to the argument expr, // a temporary DecomposedExpression, which in turn holds references to // operands, possibly temporary as well. // It should immediately be passed to handleResult; if the expression // needs to be reported, its string expansion must be composed before // the temporaries are destroyed. AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const { assert( m_data.resultType != ResultWas::Unknown ); AssertionResultData data = m_data; if(m_usedStream) data.message = m_stream().oss.str(); data.decomposedExpression = &expr; // for lazy reconstruction return AssertionResult( m_assertionInfo, data ); } void ResultBuilder::reconstructExpression( std::string& dest ) const { dest = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg); } void ResultBuilder::setExceptionGuard() { m_guardException = true; } void ResultBuilder::unsetExceptionGuard() { m_guardException = false; } } // end namespace Catch // #included from: catch_tag_alias_registry.hpp #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED namespace Catch { TagAliasRegistry::~TagAliasRegistry() {} Option TagAliasRegistry::find( std::string const& alias ) const { std::map::const_iterator it = m_registry.find( alias ); if( it != m_registry.end() ) return it->second; else return Option(); } std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { std::string expandedTestSpec = unexpandedTestSpec; for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); it != itEnd; ++it ) { std::size_t pos = expandedTestSpec.find( it->first ); if( pos != std::string::npos ) { expandedTestSpec = expandedTestSpec.substr( 0, pos ) + it->second.tag + expandedTestSpec.substr( pos + it->first.size() ); } } return expandedTestSpec; } void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) { std::ostringstream oss; oss << Colour( Colour::Red ) << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << Colour( Colour::FileName ) << lineInfo << '\n'; throw std::domain_error( oss.str().c_str() ); } if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { std::ostringstream oss; oss << Colour( Colour::Red ) << "error: tag alias, \"" << alias << "\" already registered.\n" << "\tFirst seen at " << Colour( Colour::Red ) << find(alias)->lineInfo << '\n' << Colour( Colour::Red ) << "\tRedefined at " << Colour( Colour::FileName) << lineInfo << '\n'; throw std::domain_error( oss.str().c_str() ); } } ITagAliasRegistry::~ITagAliasRegistry() {} ITagAliasRegistry const& ITagAliasRegistry::get() { return getRegistryHub().getTagAliasRegistry(); } RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { getMutableRegistryHub().registerTagAlias( alias, tag, lineInfo ); } } // end namespace Catch // #included from: catch_matchers_string.hpp namespace Catch { namespace Matchers { namespace StdString { CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) : m_caseSensitivity( caseSensitivity ), m_str( adjustString( str ) ) {} std::string CasedString::adjustString( std::string const& str ) const { return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; } std::string CasedString::caseSensitivitySuffix() const { return m_caseSensitivity == CaseSensitive::No ? " (case insensitive)" : std::string(); } StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) : m_comparator( comparator ), m_operation( operation ) { } std::string StringMatcherBase::describe() const { std::string description; description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + m_comparator.caseSensitivitySuffix().size()); description += m_operation; description += ": \""; description += m_comparator.m_str; description += "\""; description += m_comparator.caseSensitivitySuffix(); return description; } EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} bool EqualsMatcher::match( std::string const& source ) const { return m_comparator.adjustString( source ) == m_comparator.m_str; } ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} bool ContainsMatcher::match( std::string const& source ) const { return contains( m_comparator.adjustString( source ), m_comparator.m_str ); } StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} bool StartsWithMatcher::match( std::string const& source ) const { return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); } EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} bool EndsWithMatcher::match( std::string const& source ) const { return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); } } // namespace StdString StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); } StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); } StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); } StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); } } // namespace Matchers } // namespace Catch // #included from: ../reporters/catch_reporter_multi.hpp #define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED namespace Catch { class MultipleReporters : public SharedImpl { typedef std::vector > Reporters; Reporters m_reporters; public: void add( Ptr const& reporter ) { m_reporters.push_back( reporter ); } public: // IStreamingReporter virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { return m_reporters[0]->getPreferences(); } virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->noMatchingTestCases( spec ); } virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testRunStarting( testRunInfo ); } virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testGroupStarting( groupInfo ); } virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testCaseStarting( testInfo ); } virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->sectionStarting( sectionInfo ); } virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->assertionStarting( assertionInfo ); } // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { bool clearBuffer = false; for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) clearBuffer |= (*it)->assertionEnded( assertionStats ); return clearBuffer; } virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->sectionEnded( sectionStats ); } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testCaseEnded( testCaseStats ); } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testGroupEnded( testGroupStats ); } virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testRunEnded( testRunStats ); } virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->skipTest( testInfo ); } virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE { return this; } }; Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { Ptr resultingReporter; if( existingReporter ) { MultipleReporters* multi = existingReporter->tryAsMulti(); if( !multi ) { multi = new MultipleReporters; resultingReporter = Ptr( multi ); if( existingReporter ) multi->add( existingReporter ); } else resultingReporter = existingReporter; multi->add( additionalReporter ); } else resultingReporter = additionalReporter; return resultingReporter; } } // end namespace Catch // #included from: ../reporters/catch_reporter_xml.hpp #define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED // #included from: catch_reporter_bases.hpp #define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED #include #include #include #include namespace Catch { namespace { // Because formatting using c++ streams is stateful, drop down to C is required // Alternatively we could use stringstream, but its performance is... not good. std::string getFormattedDuration( double duration ) { // Max exponent + 1 is required to represent the whole part // + 1 for decimal point // + 3 for the 3 decimal places // + 1 for null terminator const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; char buffer[maxDoubleSize]; // Save previous errno, to prevent sprintf from overwriting it ErrnoGuard guard; #ifdef _MSC_VER sprintf_s(buffer, "%.3f", duration); #else sprintf(buffer, "%.3f", duration); #endif return std::string(buffer); } } struct StreamingReporterBase : SharedImpl { StreamingReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = false; } virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { return m_reporterPrefs; } virtual ~StreamingReporterBase() CATCH_OVERRIDE; virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { currentTestRunInfo = _testRunInfo; } virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { currentGroupInfo = _groupInfo; } virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { currentTestCaseInfo = _testInfo; } virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_sectionStack.push_back( _sectionInfo ); } virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { m_sectionStack.pop_back(); } virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); } virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { currentGroupInfo.reset(); } virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); currentGroupInfo.reset(); currentTestRunInfo.reset(); } virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { // Don't do anything with this by default. // It can optionally be overridden in the derived class. } Ptr m_config; std::ostream& stream; LazyStat currentTestRunInfo; LazyStat currentGroupInfo; LazyStat currentTestCaseInfo; std::vector m_sectionStack; ReporterPreferences m_reporterPrefs; }; struct CumulativeReporterBase : SharedImpl { template struct Node : SharedImpl<> { explicit Node( T const& _value ) : value( _value ) {} virtual ~Node() {} typedef std::vector > ChildNodes; T value; ChildNodes children; }; struct SectionNode : SharedImpl<> { explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} virtual ~SectionNode(); bool operator == ( SectionNode const& other ) const { return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; } bool operator == ( Ptr const& other ) const { return operator==( *other ); } SectionStats stats; typedef std::vector > ChildSections; typedef std::vector Assertions; ChildSections childSections; Assertions assertions; std::string stdOut; std::string stdErr; }; struct BySectionInfo { BySectionInfo( SectionInfo const& other ) : m_other( other ) {} BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} bool operator() ( Ptr const& node ) const { return ((node->stats.sectionInfo.name == m_other.name) && (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); } private: void operator=( BySectionInfo const& ); SectionInfo const& m_other; }; typedef Node TestCaseNode; typedef Node TestGroupNode; typedef Node TestRunNode; CumulativeReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = false; } ~CumulativeReporterBase(); virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { return m_reporterPrefs; } virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); Ptr node; if( m_sectionStack.empty() ) { if( !m_rootSection ) m_rootSection = new SectionNode( incompleteStats ); node = m_rootSection; } else { SectionNode& parentNode = *m_sectionStack.back(); SectionNode::ChildSections::const_iterator it = std::find_if( parentNode.childSections.begin(), parentNode.childSections.end(), BySectionInfo( sectionInfo ) ); if( it == parentNode.childSections.end() ) { node = new SectionNode( incompleteStats ); parentNode.childSections.push_back( node ); } else node = *it; } m_sectionStack.push_back( node ); m_deepestSection = node; } virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { assert( !m_sectionStack.empty() ); SectionNode& sectionNode = *m_sectionStack.back(); sectionNode.assertions.push_back( assertionStats ); // AssertionResult holds a pointer to a temporary DecomposedExpression, // which getExpandedExpression() calls to build the expression string. // Our section stack copy of the assertionResult will likely outlive the // temporary, so it must be expanded or discarded now to avoid calling // a destroyed object later. prepareExpandedExpression( sectionNode.assertions.back().assertionResult ); return true; } virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { assert( !m_sectionStack.empty() ); SectionNode& node = *m_sectionStack.back(); node.stats = sectionStats; m_sectionStack.pop_back(); } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { Ptr node = new TestCaseNode( testCaseStats ); assert( m_sectionStack.size() == 0 ); node->children.push_back( m_rootSection ); m_testCases.push_back( node ); m_rootSection.reset(); assert( m_deepestSection ); m_deepestSection->stdOut = testCaseStats.stdOut; m_deepestSection->stdErr = testCaseStats.stdErr; } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { Ptr node = new TestGroupNode( testGroupStats ); node->children.swap( m_testCases ); m_testGroups.push_back( node ); } virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { Ptr node = new TestRunNode( testRunStats ); node->children.swap( m_testGroups ); m_testRuns.push_back( node ); testRunEndedCumulative(); } virtual void testRunEndedCumulative() = 0; virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} virtual void prepareExpandedExpression( AssertionResult& result ) const { if( result.isOk() ) result.discardDecomposedExpression(); else result.expandDecomposedExpression(); } Ptr m_config; std::ostream& stream; std::vector m_assertions; std::vector > > m_sections; std::vector > m_testCases; std::vector > m_testGroups; std::vector > m_testRuns; Ptr m_rootSection; Ptr m_deepestSection; std::vector > m_sectionStack; ReporterPreferences m_reporterPrefs; }; template char const* getLineOfChars() { static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; if( !*line ) { std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; } return line; } struct TestEventListenerBase : StreamingReporterBase { TestEventListenerBase( ReporterConfig const& _config ) : StreamingReporterBase( _config ) {} virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { return false; } }; } // end namespace Catch // #included from: ../internal/catch_reporter_registrars.hpp #define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED namespace Catch { template class LegacyReporterRegistrar { class ReporterFactory : public IReporterFactory { virtual IStreamingReporter* create( ReporterConfig const& config ) const { return new LegacyReporterAdapter( new T( config ) ); } virtual std::string getDescription() const { return T::getDescription(); } }; public: LegacyReporterRegistrar( std::string const& name ) { getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } }; template class ReporterRegistrar { class ReporterFactory : public SharedImpl { // *** Please Note ***: // - If you end up here looking at a compiler error because it's trying to register // your custom reporter class be aware that the native reporter interface has changed // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. // However please consider updating to the new interface as the old one is now // deprecated and will probably be removed quite soon! // Please contact me via github if you have any questions at all about this. // In fact, ideally, please contact me anyway to let me know you've hit this - as I have // no idea who is actually using custom reporters at all (possibly no-one!). // The new interface is designed to minimise exposure to interface changes in the future. virtual IStreamingReporter* create( ReporterConfig const& config ) const { return new T( config ); } virtual std::string getDescription() const { return T::getDescription(); } }; public: ReporterRegistrar( std::string const& name ) { getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } }; template class ListenerRegistrar { class ListenerFactory : public SharedImpl { virtual IStreamingReporter* create( ReporterConfig const& config ) const { return new T( config ); } virtual std::string getDescription() const { return std::string(); } }; public: ListenerRegistrar() { getMutableRegistryHub().registerListener( new ListenerFactory() ); } }; } #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } // Deprecated - use the form without INTERNAL_ #define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } #define CATCH_REGISTER_LISTENER( listenerType ) \ namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } // #included from: ../internal/catch_xmlwriter.hpp #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #include #include #include #include namespace Catch { class XmlEncode { public: enum ForWhat { ForTextNodes, ForAttributes }; XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) : m_str( str ), m_forWhat( forWhat ) {} void encodeTo( std::ostream& os ) const { // Apostrophe escaping not necessary if we always use " to write attributes // (see: http://www.w3.org/TR/xml/#syntax) for( std::size_t i = 0; i < m_str.size(); ++ i ) { char c = m_str[i]; switch( c ) { case '<': os << "<"; break; case '&': os << "&"; break; case '>': // See: http://www.w3.org/TR/xml/#syntax if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) os << ">"; else os << c; break; case '\"': if( m_forWhat == ForAttributes ) os << """; else os << c; break; default: // Escape control chars - based on contribution by @espenalb in PR #465 and // by @mrpi PR #588 if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) { // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast( c ); } else os << c; } } } friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { xmlEncode.encodeTo( os ); return os; } private: std::string m_str; ForWhat m_forWhat; }; class XmlWriter { public: class ScopedElement { public: ScopedElement( XmlWriter* writer ) : m_writer( writer ) {} ScopedElement( ScopedElement const& other ) : m_writer( other.m_writer ){ other.m_writer = CATCH_NULL; } ~ScopedElement() { if( m_writer ) m_writer->endElement(); } ScopedElement& writeText( std::string const& text, bool indent = true ) { m_writer->writeText( text, indent ); return *this; } template ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { m_writer->writeAttribute( name, attribute ); return *this; } private: mutable XmlWriter* m_writer; }; XmlWriter() : m_tagIsOpen( false ), m_needsNewline( false ), m_os( Catch::cout() ) { writeDeclaration(); } XmlWriter( std::ostream& os ) : m_tagIsOpen( false ), m_needsNewline( false ), m_os( os ) { writeDeclaration(); } ~XmlWriter() { while( !m_tags.empty() ) endElement(); } XmlWriter& startElement( std::string const& name ) { ensureTagClosed(); newlineIfNecessary(); m_os << m_indent << '<' << name; m_tags.push_back( name ); m_indent += " "; m_tagIsOpen = true; return *this; } ScopedElement scopedElement( std::string const& name ) { ScopedElement scoped( this ); startElement( name ); return scoped; } XmlWriter& endElement() { newlineIfNecessary(); m_indent = m_indent.substr( 0, m_indent.size()-2 ); if( m_tagIsOpen ) { m_os << "/>"; m_tagIsOpen = false; } else { m_os << m_indent << ""; } m_os << std::endl; m_tags.pop_back(); return *this; } XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { if( !name.empty() && !attribute.empty() ) m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; return *this; } XmlWriter& writeAttribute( std::string const& name, bool attribute ) { m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; return *this; } template XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { std::ostringstream oss; oss << attribute; return writeAttribute( name, oss.str() ); } XmlWriter& writeText( std::string const& text, bool indent = true ) { if( !text.empty() ){ bool tagWasOpen = m_tagIsOpen; ensureTagClosed(); if( tagWasOpen && indent ) m_os << m_indent; m_os << XmlEncode( text ); m_needsNewline = true; } return *this; } XmlWriter& writeComment( std::string const& text ) { ensureTagClosed(); m_os << m_indent << ""; m_needsNewline = true; return *this; } void writeStylesheetRef( std::string const& url ) { m_os << "\n"; } XmlWriter& writeBlankLine() { ensureTagClosed(); m_os << '\n'; return *this; } void ensureTagClosed() { if( m_tagIsOpen ) { m_os << ">" << std::endl; m_tagIsOpen = false; } } private: XmlWriter( XmlWriter const& ); void operator=( XmlWriter const& ); void writeDeclaration() { m_os << "\n"; } void newlineIfNecessary() { if( m_needsNewline ) { m_os << std::endl; m_needsNewline = false; } } bool m_tagIsOpen; bool m_needsNewline; std::vector m_tags; std::string m_indent; std::ostream& m_os; }; } namespace Catch { class XmlReporter : public StreamingReporterBase { public: XmlReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_xml(_config.stream()), m_sectionDepth( 0 ) { m_reporterPrefs.shouldRedirectStdOut = true; } virtual ~XmlReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as an XML document"; } virtual std::string getStylesheetRef() const { return std::string(); } void writeSourceInfo( SourceLineInfo const& sourceInfo ) { m_xml .writeAttribute( "filename", sourceInfo.file ) .writeAttribute( "line", sourceInfo.line ); } public: // StreamingReporterBase virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { StreamingReporterBase::noMatchingTestCases( s ); } virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testRunStarting( testInfo ); std::string stylesheetRef = getStylesheetRef(); if( !stylesheetRef.empty() ) m_xml.writeStylesheetRef( stylesheetRef ); m_xml.startElement( "Catch" ); if( !m_config->name().empty() ) m_xml.writeAttribute( "name", m_config->name() ); } virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { StreamingReporterBase::testGroupStarting( groupInfo ); m_xml.startElement( "Group" ) .writeAttribute( "name", groupInfo.name ); } virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ) .writeAttribute( "name", trim( testInfo.name ) ) .writeAttribute( "description", testInfo.description ) .writeAttribute( "tags", testInfo.tagsAsString ); writeSourceInfo( testInfo.lineInfo ); if ( m_config->showDurations() == ShowDurations::Always ) m_testCaseTimer.start(); m_xml.ensureTagClosed(); } virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) .writeAttribute( "name", trim( sectionInfo.name ) ) .writeAttribute( "description", sectionInfo.description ); writeSourceInfo( sectionInfo.lineInfo ); m_xml.ensureTagClosed(); } } virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { AssertionResult const& result = assertionStats.assertionResult; bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); if( includeResults ) { // Print any info messages in tags. for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); it != itEnd; ++it ) { if( it->type == ResultWas::Info ) { m_xml.scopedElement( "Info" ) .writeText( it->message ); } else if ( it->type == ResultWas::Warning ) { m_xml.scopedElement( "Warning" ) .writeText( it->message ); } } } // Drop out if result was successful but we're not printing them. if( !includeResults && result.getResultType() != ResultWas::Warning ) return true; // Print the expression if there is one. if( result.hasExpression() ) { m_xml.startElement( "Expression" ) .writeAttribute( "success", result.succeeded() ) .writeAttribute( "type", result.getTestMacroName() ); writeSourceInfo( result.getSourceInfo() ); m_xml.scopedElement( "Original" ) .writeText( result.getExpression() ); m_xml.scopedElement( "Expanded" ) .writeText( result.getExpandedExpression() ); } // And... Print a result applicable to each result type. switch( result.getResultType() ) { case ResultWas::ThrewException: m_xml.startElement( "Exception" ); writeSourceInfo( result.getSourceInfo() ); m_xml.writeText( result.getMessage() ); m_xml.endElement(); break; case ResultWas::FatalErrorCondition: m_xml.startElement( "FatalErrorCondition" ); writeSourceInfo( result.getSourceInfo() ); m_xml.writeText( result.getMessage() ); m_xml.endElement(); break; case ResultWas::Info: m_xml.scopedElement( "Info" ) .writeText( result.getMessage() ); break; case ResultWas::Warning: // Warning will already have been written break; case ResultWas::ExplicitFailure: m_xml.startElement( "Failure" ); writeSourceInfo( result.getSourceInfo() ); m_xml.writeText( result.getMessage() ); m_xml.endElement(); break; default: break; } if( result.hasExpression() ) m_xml.endElement(); return true; } virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { StreamingReporterBase::sectionEnded( sectionStats ); if( --m_sectionDepth > 0 ) { XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); e.writeAttribute( "successes", sectionStats.assertions.passed ); e.writeAttribute( "failures", sectionStats.assertions.failed ); e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); m_xml.endElement(); } } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( testCaseStats ); XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); if( !testCaseStats.stdOut.empty() ) m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); if( !testCaseStats.stdErr.empty() ) m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); m_xml.endElement(); } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { StreamingReporterBase::testGroupEnded( testGroupStats ); // TODO: Check testGroupStats.aborting and act accordingly. m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); m_xml.endElement(); } virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { StreamingReporterBase::testRunEnded( testRunStats ); m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testRunStats.totals.assertions.passed ) .writeAttribute( "failures", testRunStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); m_xml.endElement(); } private: Timer m_testCaseTimer; XmlWriter m_xml; int m_sectionDepth; }; INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) } // end namespace Catch // #included from: ../reporters/catch_reporter_junit.hpp #define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED #include namespace Catch { namespace { std::string getCurrentTimestamp() { // Beware, this is not reentrant because of backward compatibility issues // Also, UTC only, again because of backward compatibility (%z is C++11) time_t rawtime; std::time(&rawtime); const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z"); #ifdef _MSC_VER std::tm timeInfo = {}; gmtime_s(&timeInfo, &rawtime); #else std::tm* timeInfo; timeInfo = std::gmtime(&rawtime); #endif char timeStamp[timeStampSize]; const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; #ifdef _MSC_VER std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); #else std::strftime(timeStamp, timeStampSize, fmt, timeInfo); #endif return std::string(timeStamp); } } class JunitReporter : public CumulativeReporterBase { public: JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), xml( _config.stream() ), unexpectedExceptions( 0 ), m_okToFail( false ) { m_reporterPrefs.shouldRedirectStdOut = true; } virtual ~JunitReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results in an XML format that looks like Ant's junitreport target"; } virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { CumulativeReporterBase::testRunStarting( runInfo ); xml.startElement( "testsuites" ); } virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { suiteTimer.start(); stdOutForSuite.str(""); stdErrForSuite.str(""); unexpectedExceptions = 0; CumulativeReporterBase::testGroupStarting( groupInfo ); } virtual void testCaseStarting( TestCaseInfo const& testCaseInfo ) CATCH_OVERRIDE { m_okToFail = testCaseInfo.okToFail(); } virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) unexpectedExceptions++; return CumulativeReporterBase::assertionEnded( assertionStats ); } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { stdOutForSuite << testCaseStats.stdOut; stdErrForSuite << testCaseStats.stdErr; CumulativeReporterBase::testCaseEnded( testCaseStats ); } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { double suiteTime = suiteTimer.getElapsedSeconds(); CumulativeReporterBase::testGroupEnded( testGroupStats ); writeGroup( *m_testGroups.back(), suiteTime ); } virtual void testRunEndedCumulative() CATCH_OVERRIDE { xml.endElement(); } void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); TestGroupStats const& stats = groupNode.value; xml.writeAttribute( "name", stats.groupInfo.name ); xml.writeAttribute( "errors", unexpectedExceptions ); xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); xml.writeAttribute( "tests", stats.totals.assertions.total() ); xml.writeAttribute( "hostname", "tbd" ); // !TBD if( m_config->showDurations() == ShowDurations::Never ) xml.writeAttribute( "time", "" ); else xml.writeAttribute( "time", suiteTime ); xml.writeAttribute( "timestamp", getCurrentTimestamp() ); // Write test cases for( TestGroupNode::ChildNodes::const_iterator it = groupNode.children.begin(), itEnd = groupNode.children.end(); it != itEnd; ++it ) writeTestCase( **it ); xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); } void writeTestCase( TestCaseNode const& testCaseNode ) { TestCaseStats const& stats = testCaseNode.value; // All test cases have exactly one section - which represents the // test case itself. That section may have 0-n nested sections assert( testCaseNode.children.size() == 1 ); SectionNode const& rootSection = *testCaseNode.children.front(); std::string className = stats.testInfo.className; if( className.empty() ) { if( rootSection.childSections.empty() ) className = "global"; } writeSection( className, "", rootSection ); } void writeSection( std::string const& className, std::string const& rootName, SectionNode const& sectionNode ) { std::string name = trim( sectionNode.stats.sectionInfo.name ); if( !rootName.empty() ) name = rootName + '/' + name; if( !sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty() ) { XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); if( className.empty() ) { xml.writeAttribute( "classname", name ); xml.writeAttribute( "name", "root" ); } else { xml.writeAttribute( "classname", className ); xml.writeAttribute( "name", name ); } xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); writeAssertions( sectionNode ); if( !sectionNode.stdOut.empty() ) xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); if( !sectionNode.stdErr.empty() ) xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); } for( SectionNode::ChildSections::const_iterator it = sectionNode.childSections.begin(), itEnd = sectionNode.childSections.end(); it != itEnd; ++it ) if( className.empty() ) writeSection( name, "", **it ); else writeSection( className, name, **it ); } void writeAssertions( SectionNode const& sectionNode ) { for( SectionNode::Assertions::const_iterator it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); it != itEnd; ++it ) writeAssertion( *it ); } void writeAssertion( AssertionStats const& stats ) { AssertionResult const& result = stats.assertionResult; if( !result.isOk() ) { std::string elementName; switch( result.getResultType() ) { case ResultWas::ThrewException: case ResultWas::FatalErrorCondition: elementName = "error"; break; case ResultWas::ExplicitFailure: elementName = "failure"; break; case ResultWas::ExpressionFailed: elementName = "failure"; break; case ResultWas::DidntThrowException: elementName = "failure"; break; // We should never see these here: case ResultWas::Info: case ResultWas::Warning: case ResultWas::Ok: case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: elementName = "internalError"; break; } XmlWriter::ScopedElement e = xml.scopedElement( elementName ); xml.writeAttribute( "message", result.getExpandedExpression() ); xml.writeAttribute( "type", result.getTestMacroName() ); std::ostringstream oss; if( !result.getMessage().empty() ) oss << result.getMessage() << '\n'; for( std::vector::const_iterator it = stats.infoMessages.begin(), itEnd = stats.infoMessages.end(); it != itEnd; ++it ) if( it->type == ResultWas::Info ) oss << it->message << '\n'; oss << "at " << result.getSourceInfo(); xml.writeText( oss.str(), false ); } } XmlWriter xml; Timer suiteTimer; std::ostringstream stdOutForSuite; std::ostringstream stdErrForSuite; unsigned int unexpectedExceptions; bool m_okToFail; }; INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) } // end namespace Catch // #included from: ../reporters/catch_reporter_console.hpp #define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED #include #include namespace Catch { struct ConsoleReporter : StreamingReporterBase { ConsoleReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_headerPrinted( false ) {} virtual ~ConsoleReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as plain lines of text"; } virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { stream << "No test cases matched '" << spec << '\'' << std::endl; } virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { AssertionResult const& result = _assertionStats.assertionResult; bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); // Drop out if result was successful but we're not printing them. if( !includeResults && result.getResultType() != ResultWas::Warning ) return false; lazyPrint(); AssertionPrinter printer( stream, _assertionStats, includeResults ); printer.print(); stream << std::endl; return true; } virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_headerPrinted = false; StreamingReporterBase::sectionStarting( _sectionInfo ); } virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { if( _sectionStats.missingAssertions ) { lazyPrint(); Colour colour( Colour::ResultError ); if( m_sectionStack.size() > 1 ) stream << "\nNo assertions in section"; else stream << "\nNo assertions in test case"; stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; } if( m_config->showDurations() == ShowDurations::Always ) { stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; } if( m_headerPrinted ) { m_headerPrinted = false; } StreamingReporterBase::sectionEnded( _sectionStats ); } virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( _testCaseStats ); m_headerPrinted = false; } virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { if( currentGroupInfo.used ) { printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; printTotals( _testGroupStats.totals ); stream << '\n' << std::endl; } StreamingReporterBase::testGroupEnded( _testGroupStats ); } virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { printTotalsDivider( _testRunStats.totals ); printTotals( _testRunStats.totals ); stream << std::endl; StreamingReporterBase::testRunEnded( _testRunStats ); } private: class AssertionPrinter { void operator= ( AssertionPrinter const& ); public: AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) : stream( _stream ), stats( _stats ), result( _stats.assertionResult ), colour( Colour::None ), message( result.getMessage() ), messages( _stats.infoMessages ), printInfoMessages( _printInfoMessages ) { switch( result.getResultType() ) { case ResultWas::Ok: colour = Colour::Success; passOrFail = "PASSED"; //if( result.hasMessage() ) if( _stats.infoMessages.size() == 1 ) messageLabel = "with message"; if( _stats.infoMessages.size() > 1 ) messageLabel = "with messages"; break; case ResultWas::ExpressionFailed: if( result.isOk() ) { colour = Colour::Success; passOrFail = "FAILED - but was ok"; } else { colour = Colour::Error; passOrFail = "FAILED"; } if( _stats.infoMessages.size() == 1 ) messageLabel = "with message"; if( _stats.infoMessages.size() > 1 ) messageLabel = "with messages"; break; case ResultWas::ThrewException: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "due to unexpected exception with "; if (_stats.infoMessages.size() == 1) messageLabel += "message"; if (_stats.infoMessages.size() > 1) messageLabel += "messages"; break; case ResultWas::FatalErrorCondition: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "due to a fatal error condition"; break; case ResultWas::DidntThrowException: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "because no exception was thrown where one was expected"; break; case ResultWas::Info: messageLabel = "info"; break; case ResultWas::Warning: messageLabel = "warning"; break; case ResultWas::ExplicitFailure: passOrFail = "FAILED"; colour = Colour::Error; if( _stats.infoMessages.size() == 1 ) messageLabel = "explicitly with message"; if( _stats.infoMessages.size() > 1 ) messageLabel = "explicitly with messages"; break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: passOrFail = "** internal error **"; colour = Colour::Error; break; } } void print() const { printSourceInfo(); if( stats.totals.assertions.total() > 0 ) { if( result.isOk() ) stream << '\n'; printResultType(); printOriginalExpression(); printReconstructedExpression(); } else { stream << '\n'; } printMessage(); } private: void printResultType() const { if( !passOrFail.empty() ) { Colour colourGuard( colour ); stream << passOrFail << ":\n"; } } void printOriginalExpression() const { if( result.hasExpression() ) { Colour colourGuard( Colour::OriginalExpression ); stream << " "; stream << result.getExpressionInMacro(); stream << '\n'; } } void printReconstructedExpression() const { if( result.hasExpandedExpression() ) { stream << "with expansion:\n"; Colour colourGuard( Colour::ReconstructedExpression ); stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n'; } } void printMessage() const { if( !messageLabel.empty() ) stream << messageLabel << ':' << '\n'; for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); it != itEnd; ++it ) { // If this assertion is a warning ignore any INFO messages if( printInfoMessages || it->type != ResultWas::Info ) stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n'; } } void printSourceInfo() const { Colour colourGuard( Colour::FileName ); stream << result.getSourceInfo() << ": "; } std::ostream& stream; AssertionStats const& stats; AssertionResult const& result; Colour::Code colour; std::string passOrFail; std::string messageLabel; std::string message; std::vector messages; bool printInfoMessages; }; void lazyPrint() { if( !currentTestRunInfo.used ) lazyPrintRunInfo(); if( !currentGroupInfo.used ) lazyPrintGroupInfo(); if( !m_headerPrinted ) { printTestCaseAndSectionHeader(); m_headerPrinted = true; } } void lazyPrintRunInfo() { stream << '\n' << getLineOfChars<'~'>() << '\n'; Colour colour( Colour::SecondaryText ); stream << currentTestRunInfo->name << " is a Catch v" << libraryVersion() << " host application.\n" << "Run with -? for options\n\n"; if( m_config->rngSeed() != 0 ) stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; currentTestRunInfo.used = true; } void lazyPrintGroupInfo() { if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { printClosedHeader( "Group: " + currentGroupInfo->name ); currentGroupInfo.used = true; } } void printTestCaseAndSectionHeader() { assert( !m_sectionStack.empty() ); printOpenHeader( currentTestCaseInfo->name ); if( m_sectionStack.size() > 1 ) { Colour colourGuard( Colour::Headers ); std::vector::const_iterator it = m_sectionStack.begin()+1, // Skip first section (test case) itEnd = m_sectionStack.end(); for( ; it != itEnd; ++it ) printHeaderString( it->name, 2 ); } SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; if( !lineInfo.empty() ){ stream << getLineOfChars<'-'>() << '\n'; Colour colourGuard( Colour::FileName ); stream << lineInfo << '\n'; } stream << getLineOfChars<'.'>() << '\n' << std::endl; } void printClosedHeader( std::string const& _name ) { printOpenHeader( _name ); stream << getLineOfChars<'.'>() << '\n'; } void printOpenHeader( std::string const& _name ) { stream << getLineOfChars<'-'>() << '\n'; { Colour colourGuard( Colour::Headers ); printHeaderString( _name ); } } // if string has a : in first line will set indent to follow it on // subsequent lines void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { std::size_t i = _string.find( ": " ); if( i != std::string::npos ) i+=2; else i = 0; stream << Text( _string, TextAttributes() .setIndent( indent+i) .setInitialIndent( indent ) ) << '\n'; } struct SummaryColumn { SummaryColumn( std::string const& _label, Colour::Code _colour ) : label( _label ), colour( _colour ) {} SummaryColumn addRow( std::size_t count ) { std::ostringstream oss; oss << count; std::string row = oss.str(); for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { while( it->size() < row.size() ) *it = ' ' + *it; while( it->size() > row.size() ) row = ' ' + row; } rows.push_back( row ); return *this; } std::string label; Colour::Code colour; std::vector rows; }; void printTotals( Totals const& totals ) { if( totals.testCases.total() == 0 ) { stream << Colour( Colour::Warning ) << "No tests ran\n"; } else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) { stream << Colour( Colour::ResultSuccess ) << "All tests passed"; stream << " (" << pluralise( totals.assertions.passed, "assertion" ) << " in " << pluralise( totals.testCases.passed, "test case" ) << ')' << '\n'; } else { std::vector columns; columns.push_back( SummaryColumn( "", Colour::None ) .addRow( totals.testCases.total() ) .addRow( totals.assertions.total() ) ); columns.push_back( SummaryColumn( "passed", Colour::Success ) .addRow( totals.testCases.passed ) .addRow( totals.assertions.passed ) ); columns.push_back( SummaryColumn( "failed", Colour::ResultError ) .addRow( totals.testCases.failed ) .addRow( totals.assertions.failed ) ); columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) .addRow( totals.testCases.failedButOk ) .addRow( totals.assertions.failedButOk ) ); printSummaryRow( "test cases", columns, 0 ); printSummaryRow( "assertions", columns, 1 ); } } void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { std::string value = it->rows[row]; if( it->label.empty() ) { stream << label << ": "; if( value != "0" ) stream << value; else stream << Colour( Colour::Warning ) << "- none -"; } else if( value != "0" ) { stream << Colour( Colour::LightGrey ) << " | "; stream << Colour( it->colour ) << value << ' ' << it->label; } } stream << '\n'; } static std::size_t makeRatio( std::size_t number, std::size_t total ) { std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; return ( ratio == 0 && number > 0 ) ? 1 : ratio; } static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { if( i > j && i > k ) return i; else if( j > k ) return j; else return k; } void printTotalsDivider( Totals const& totals ) { if( totals.testCases.total() > 0 ) { std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) findMax( failedRatio, failedButOkRatio, passedRatio )++; while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) findMax( failedRatio, failedButOkRatio, passedRatio )--; stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); if( totals.testCases.allPassed() ) stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); else stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); } else { stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); } stream << '\n'; } void printSummaryDivider() { stream << getLineOfChars<'-'>() << '\n'; } private: bool m_headerPrinted; }; INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) } // end namespace Catch // #included from: ../reporters/catch_reporter_compact.hpp #define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED namespace Catch { struct CompactReporter : StreamingReporterBase { CompactReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ) {} virtual ~CompactReporter(); static std::string getDescription() { return "Reports test results on a single line, suitable for IDEs"; } virtual ReporterPreferences getPreferences() const { ReporterPreferences prefs; prefs.shouldRedirectStdOut = false; return prefs; } virtual void noMatchingTestCases( std::string const& spec ) { stream << "No test cases matched '" << spec << '\'' << std::endl; } virtual void assertionStarting( AssertionInfo const& ) {} virtual bool assertionEnded( AssertionStats const& _assertionStats ) { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; // Drop out if result was successful and we're not printing those if( !m_config->includeSuccessfulResults() && result.isOk() ) { if( result.getResultType() != ResultWas::Warning ) return false; printInfoMessages = false; } AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); printer.print(); stream << std::endl; return true; } virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE { if (m_config->showDurations() == ShowDurations::Always) { stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; } } virtual void testRunEnded( TestRunStats const& _testRunStats ) { printTotals( _testRunStats.totals ); stream << '\n' << std::endl; StreamingReporterBase::testRunEnded( _testRunStats ); } private: class AssertionPrinter { void operator= ( AssertionPrinter const& ); public: AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) : stream( _stream ) , stats( _stats ) , result( _stats.assertionResult ) , messages( _stats.infoMessages ) , itMessage( _stats.infoMessages.begin() ) , printInfoMessages( _printInfoMessages ) {} void print() { printSourceInfo(); itMessage = messages.begin(); switch( result.getResultType() ) { case ResultWas::Ok: printResultType( Colour::ResultSuccess, passedString() ); printOriginalExpression(); printReconstructedExpression(); if ( ! result.hasExpression() ) printRemainingMessages( Colour::None ); else printRemainingMessages(); break; case ResultWas::ExpressionFailed: if( result.isOk() ) printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); else printResultType( Colour::Error, failedString() ); printOriginalExpression(); printReconstructedExpression(); printRemainingMessages(); break; case ResultWas::ThrewException: printResultType( Colour::Error, failedString() ); printIssue( "unexpected exception with message:" ); printMessage(); printExpressionWas(); printRemainingMessages(); break; case ResultWas::FatalErrorCondition: printResultType( Colour::Error, failedString() ); printIssue( "fatal error condition with message:" ); printMessage(); printExpressionWas(); printRemainingMessages(); break; case ResultWas::DidntThrowException: printResultType( Colour::Error, failedString() ); printIssue( "expected exception, got none" ); printExpressionWas(); printRemainingMessages(); break; case ResultWas::Info: printResultType( Colour::None, "info" ); printMessage(); printRemainingMessages(); break; case ResultWas::Warning: printResultType( Colour::None, "warning" ); printMessage(); printRemainingMessages(); break; case ResultWas::ExplicitFailure: printResultType( Colour::Error, failedString() ); printIssue( "explicitly" ); printRemainingMessages( Colour::None ); break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: printResultType( Colour::Error, "** internal error **" ); break; } } private: // Colour::LightGrey static Colour::Code dimColour() { return Colour::FileName; } #ifdef CATCH_PLATFORM_MAC static const char* failedString() { return "FAILED"; } static const char* passedString() { return "PASSED"; } #else static const char* failedString() { return "failed"; } static const char* passedString() { return "passed"; } #endif void printSourceInfo() const { Colour colourGuard( Colour::FileName ); stream << result.getSourceInfo() << ':'; } void printResultType( Colour::Code colour, std::string const& passOrFail ) const { if( !passOrFail.empty() ) { { Colour colourGuard( colour ); stream << ' ' << passOrFail; } stream << ':'; } } void printIssue( std::string const& issue ) const { stream << ' ' << issue; } void printExpressionWas() { if( result.hasExpression() ) { stream << ';'; { Colour colour( dimColour() ); stream << " expression was:"; } printOriginalExpression(); } } void printOriginalExpression() const { if( result.hasExpression() ) { stream << ' ' << result.getExpression(); } } void printReconstructedExpression() const { if( result.hasExpandedExpression() ) { { Colour colour( dimColour() ); stream << " for: "; } stream << result.getExpandedExpression(); } } void printMessage() { if ( itMessage != messages.end() ) { stream << " '" << itMessage->message << '\''; ++itMessage; } } void printRemainingMessages( Colour::Code colour = dimColour() ) { if ( itMessage == messages.end() ) return; // using messages.end() directly yields compilation error: std::vector::const_iterator itEnd = messages.end(); const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); { Colour colourGuard( colour ); stream << " with " << pluralise( N, "message" ) << ':'; } for(; itMessage != itEnd; ) { // If this assertion is a warning ignore any INFO messages if( printInfoMessages || itMessage->type != ResultWas::Info ) { stream << " '" << itMessage->message << '\''; if ( ++itMessage != itEnd ) { Colour colourGuard( dimColour() ); stream << " and"; } } } } private: std::ostream& stream; AssertionStats const& stats; AssertionResult const& result; std::vector messages; std::vector::const_iterator itMessage; bool printInfoMessages; }; // Colour, message variants: // - white: No tests ran. // - red: Failed [both/all] N test cases, failed [both/all] M assertions. // - white: Passed [both/all] N test cases (no assertions). // - red: Failed N tests cases, failed M assertions. // - green: Passed [both/all] N tests cases with M assertions. std::string bothOrAll( std::size_t count ) const { return count == 1 ? std::string() : count == 2 ? "both " : "all " ; } void printTotals( const Totals& totals ) const { if( totals.testCases.total() == 0 ) { stream << "No tests ran."; } else if( totals.testCases.failed == totals.testCases.total() ) { Colour colour( Colour::ResultError ); const std::string qualify_assertions_failed = totals.assertions.failed == totals.assertions.total() ? bothOrAll( totals.assertions.failed ) : std::string(); stream << "Failed " << bothOrAll( totals.testCases.failed ) << pluralise( totals.testCases.failed, "test case" ) << ", " "failed " << qualify_assertions_failed << pluralise( totals.assertions.failed, "assertion" ) << '.'; } else if( totals.assertions.total() == 0 ) { stream << "Passed " << bothOrAll( totals.testCases.total() ) << pluralise( totals.testCases.total(), "test case" ) << " (no assertions)."; } else if( totals.assertions.failed ) { Colour colour( Colour::ResultError ); stream << "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.'; } else { Colour colour( Colour::ResultSuccess ); stream << "Passed " << bothOrAll( totals.testCases.passed ) << pluralise( totals.testCases.passed, "test case" ) << " with " << pluralise( totals.assertions.passed, "assertion" ) << '.'; } } }; INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) } // end namespace Catch namespace Catch { // These are all here to avoid warnings about not having any out of line // virtual methods NonCopyable::~NonCopyable() {} IShared::~IShared() {} IStream::~IStream() CATCH_NOEXCEPT {} FileStream::~FileStream() CATCH_NOEXCEPT {} CoutStream::~CoutStream() CATCH_NOEXCEPT {} DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} IContext::~IContext() {} IResultCapture::~IResultCapture() {} ITestCase::~ITestCase() {} ITestCaseRegistry::~ITestCaseRegistry() {} IRegistryHub::~IRegistryHub() {} IMutableRegistryHub::~IMutableRegistryHub() {} IExceptionTranslator::~IExceptionTranslator() {} IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} IReporter::~IReporter() {} IReporterFactory::~IReporterFactory() {} IReporterRegistry::~IReporterRegistry() {} IStreamingReporter::~IStreamingReporter() {} AssertionStats::~AssertionStats() {} SectionStats::~SectionStats() {} TestCaseStats::~TestCaseStats() {} TestGroupStats::~TestGroupStats() {} TestRunStats::~TestRunStats() {} CumulativeReporterBase::SectionNode::~SectionNode() {} CumulativeReporterBase::~CumulativeReporterBase() {} StreamingReporterBase::~StreamingReporterBase() {} ConsoleReporter::~ConsoleReporter() {} CompactReporter::~CompactReporter() {} IRunner::~IRunner() {} IMutableContext::~IMutableContext() {} IConfig::~IConfig() {} XmlReporter::~XmlReporter() {} JunitReporter::~JunitReporter() {} TestRegistry::~TestRegistry() {} FreeFunctionTestCase::~FreeFunctionTestCase() {} IGeneratorInfo::~IGeneratorInfo() {} IGeneratorsForTest::~IGeneratorsForTest() {} WildcardPattern::~WildcardPattern() {} TestSpec::Pattern::~Pattern() {} TestSpec::NamePattern::~NamePattern() {} TestSpec::TagPattern::~TagPattern() {} TestSpec::ExcludedPattern::~ExcludedPattern() {} Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {} void Config::dummy() {} namespace TestCaseTracking { ITracker::~ITracker() {} TrackerBase::~TrackerBase() {} SectionTracker::~SectionTracker() {} IndexTracker::~IndexTracker() {} } } #ifdef __clang__ #pragma clang diagnostic pop #endif #endif #ifdef CATCH_CONFIG_MAIN // #included from: internal/catch_default_main.hpp #define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED #ifndef __OBJC__ #if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) // Standard C/C++ Win32 Unicode wmain entry point extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { #else // Standard C/C++ main entry point int main (int argc, char * argv[]) { #endif int result = Catch::Session().run( argc, argv ); return ( result < 0xff ? result : 0xff ); } #else // __OBJC__ // Objective-C entry point int main (int argc, char * const argv[]) { #if !CATCH_ARC_ENABLED NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; #endif Catch::registerTestMethods(); int result = Catch::Session().run( argc, (char* const*)argv ); #if !CATCH_ARC_ENABLED [pool drain]; #endif return ( result < 0xff ? result : 0xff ); } #endif // __OBJC__ #endif #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED # undef CLARA_CONFIG_MAIN #endif ////// // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ #ifdef CATCH_CONFIG_PREFIX_ALL #if defined(CATCH_CONFIG_FAST_COMPILE) #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) #else #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) #endif #define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) #define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) #if defined(CATCH_CONFIG_FAST_COMPILE) #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) #else #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) #endif #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) #define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) #define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) #define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) #ifdef CATCH_CONFIG_VARIADIC_MACROS #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #else #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) #define CATCH_FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) #endif #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) #define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) #define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) #define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) // "BDD-style" convenience wrappers #ifdef CATCH_CONFIG_VARIADIC_MACROS #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) #else #define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif #define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) #define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) #define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) #define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) #define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else #if defined(CATCH_CONFIG_FAST_COMPILE) #define REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE", Catch::ResultDisposition::Normal, expr ) #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) #else #define REQUIRE( expr ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, expr ) #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) #endif #define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) #define CHECK( expr ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) #define CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) #define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) #if defined(CATCH_CONFIG_FAST_COMPILE) #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) #else #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) #endif #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) #define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) #define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) #define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) #ifdef CATCH_CONFIG_VARIADIC_MACROS #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #else #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define FAIL( msg ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) #define FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) #define SUCCEED( msg ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) #endif #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) #define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) #define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) #define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) // "BDD-style" convenience wrappers #ifdef CATCH_CONFIG_VARIADIC_MACROS #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) #else #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif #define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) #define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) #define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) #define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) #define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) using Catch::Detail::Approx; // #included from: internal/catch_reenable_warnings.h #define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(pop) # else # pragma clang diagnostic pop # endif #elif defined __GNUC__ # pragma GCC diagnostic pop #endif #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED osmium-tool-1.7.1/test/include/test.hpp000066400000000000000000000000601315004223400200640ustar00rootroot00000000000000 #include "catch.hpp" #include "exception.hpp" osmium-tool-1.7.1/test/io/000077500000000000000000000000001315004223400153645ustar00rootroot00000000000000osmium-tool-1.7.1/test/io/Makefile.in000066400000000000000000000214361315004223400174370ustar00rootroot00000000000000# # Osmium I/O tests # ================ # # To run this, run cmake as usual. Then to run with default test file, call: # # make -f BUILD_DIR/test/io/Makefile # # Look in test/io/output/report for results. All checksums in one set # must be equal, but different between sets. # # To run with a different OSM data file, use: # # make -f BUILD_DIR/test/io/Makefile INPUT=SOME_OSM_FILE # # To also create OPL files and check their checksums, call # # make -f BUILD_DIR/test/io/Makefile INPUT=SOME_OSM_FILE opl # # and look in test/io/output/report_opl for results. # # You can set these variables on the command line: # # DIR -- output directory # INPUT -- input OSM file (xml or pbf) # OSMOSIS -- path to osmosis command (used to create reference files) # DIR := @CMAKE_BINARY_DIR@/test/io/output INPUT := @CMAKE_SOURCE_DIR@/test/io/input.osm OSMOSIS := /usr/bin/osmosis OSMIUM := @CMAKE_BINARY_DIR@/src/osmium OSMIUM_CMD := $(OSMIUM) cat --overwrite --no-progress OSMIUM_FILEINFO := $(OSMIUM) fileinfo --no-progress -e -g data.crc32 ifeq ($(suffix $(INPUT)),.pbf) OSMOSIS_READ := $(OSMOSIS) --read-pbf else OSMOSIS_READ := $(OSMOSIS) --read-xml endif .PHONY: all report opl opl_input opl_files clean all: report report: $(DIR)/report opl: $(DIR)/report_opl clean: rm -f $(DIR)/* $(DIR): mkdir -p $(DIR) opl_input: $(DIR)/input.osm.opl $(DIR)/input.osm.opl: $(INPUT) $(OSMIUM_CMD) $< -o $@; \ opl_files: \ $(DIR)/osmium-xml-osmosis.osm.pbf \ $(DIR)/osmosis.osm.bz2 \ $(DIR)/osmosis-DCbMg.osm.pbf \ $(DIR)/osmosis-dCbMg.osm.pbf \ $(DIR)/osmosis-DcbMg.osm.pbf \ $(DIR)/osmosis-dcbMg.osm.pbf \ $(DIR)/osmosis-DCBMg.osm.pbf \ $(DIR)/osmium.osm.bz2 \ $(DIR)/osmium-DCbMg.osm.pbf \ $(DIR)/osmium-dCbMg.osm.pbf \ $(DIR)/osmium-DcbMg.osm.pbf \ $(DIR)/osmium-dcbMg.osm.pbf \ $(DIR)/osmosis-DCbMg-osmium.osm.pbf \ $(DIR)/osmosis-dCbMg-osmium.osm.pbf \ $(DIR)/osmosis-DcbMg-osmium.osm.pbf \ $(DIR)/osmosis-dcbMg-osmium.osm.pbf \ $(DIR)/osmium-DCbMg-osmosis.osm.pbf \ $(DIR)/osmium-dCbMg-osmosis.osm.pbf \ $(DIR)/osmium-DcbMg-osmosis.osm.pbf \ $(DIR)/osmium-dcbMg-osmosis.osm.pbf \ $(DIR)/osmosis-dCbMG.osm.pbf \ $(DIR)/osmosis-DCbmg.osm.pbf \ $(DIR)/osmium-DCbmg.osm.pbf \ $(DIR)/osmosis-DCbmg-osmium.osm.pbf \ $(DIR)/osmium-DCbmg-osmosis.osm.pbf for i in $^; do \ $(OSMIUM_CMD) $$i -o $${i%.pbf}.opl; \ done $(DIR)/osmium-DCbmg-amf.osm.opl: $(DIR)/osmium-DCbMg.osm.pbf $(OSMIUM_CMD) $^ -o $@ -fopl,add_metadata=false $(DIR)/osmium-DCbmg-amf-fake.osm.opl: $(DIR)/osmium-DCbMg.osm.opl sed -e 's/ v.* T/ T/' $^ >$@ $(DIR)/osmium-DCbmg-fake.osm.opl: $(DIR)/osmium-DCbMg.osm.opl sed -e 's/ v.* T/ v0 dV c0 t i0 u T/' $^ >$@ $(DIR)/osmium-DCbMG-fake.osm.opl: $(DIR)/osmium-DCbMg.osm.opl grep '^n' $^ | sed -e 's/[0-9][0-9] y/ y/' -e 's/\(.*\) y\([0-9]\.[0-9][0-9][0-9][0-9][0-9]\).*/\1 y\2/' -e 's/0\+$$//' >$@ grep '^[wr]' $^ >>$@ $(DIR)/report_opl: opl_input opl_files \ $(DIR)/osmium-DCbmg-fake.osm.opl \ $(DIR)/osmium-DCbMG-fake.osm.opl \ $(DIR)/osmium-DCbmg-amf.osm.opl \ $(DIR)/osmium-DCbmg-amf-fake.osm.opl echo "OPL md5sum (default):" >$@; \ md5sum $(DIR)/input.osm.opl >>$@; \ md5sum $(DIR)/*bz2.opl >>$@; \ md5sum $(DIR)/osmium-xml-osmosis.osm.opl >>$@; \ for i in $(DIR)/*Mg*.opl; do \ md5sum $$i; \ done | sort >>$@; \ echo >>$@; \ echo "OPL md5sum (non-standard granularity):" >>$@; \ for i in $(DIR)/*MG*.opl; do \ md5sum $$i; \ done | sort >>$@; \ echo >>$@; \ echo "OPL md5sum (with empty metadata):" >>$@; \ for i in $(DIR)/*mg-osm*.osm.opl $(DIR)/*mg-fake.osm.opl $(DIR)/*mg.osm.opl; do \ md5sum $$i; \ done | sort >>$@; \ echo >>$@; \ echo "OPL md5sum (without metadata):" >>$@; \ for i in $(DIR)/*-amf*.opl; do \ md5sum $$i; \ done | sort >>$@; \ echo >>$@ $(DIR)/report_default: \ $(INPUT) \ $(DIR)/osmosis.osm.bz2 \ $(DIR)/osmosis-DCbMg.osm.pbf \ $(DIR)/osmosis-dCbMg.osm.pbf \ $(DIR)/osmosis-DcbMg.osm.pbf \ $(DIR)/osmosis-dcbMg.osm.pbf \ $(DIR)/osmosis-DCBMg.osm.pbf \ $(DIR)/osmium.osm.bz2 \ $(DIR)/osmium-DCbMg.osm.pbf \ $(DIR)/osmium-dCbMg.osm.pbf \ $(DIR)/osmium-DcbMg.osm.pbf \ $(DIR)/osmium-dcbMg.osm.pbf \ $(DIR)/osmosis-DCbMg-osmium.osm.pbf \ $(DIR)/osmosis-dCbMg-osmium.osm.pbf \ $(DIR)/osmosis-DcbMg-osmium.osm.pbf \ $(DIR)/osmosis-dcbMg-osmium.osm.pbf \ $(DIR)/osmium-xml-osmosis.osm.pbf \ $(DIR)/osmium-DCbMg-osmosis.osm.pbf \ $(DIR)/osmium-dCbMg-osmosis.osm.pbf \ $(DIR)/osmium-DcbMg-osmosis.osm.pbf \ $(DIR)/osmium-dcbMg-osmosis.osm.pbf echo "Default:" >$@; \ for i in $^; do \ filename=`basename $$i`; \ crc=`$(OSMIUM_FILEINFO) $$i`; \ echo $$crc $$filename >>$@; \ done; \ echo >>$@ $(DIR)/report_granularity: \ $(DIR)/osmosis-dCbMG.osm.pbf echo "Non-standard granularity:" >$@; \ for i in $^; do \ filename=`basename $$i`; \ crc=`$(OSMIUM_FILEINFO) $$i`; \ echo $$crc $$filename >>$@; \ done; \ echo >>$@ $(DIR)/report_without_metadata: \ $(DIR)/osmosis-DCbmg.osm.pbf \ $(DIR)/osmium-DCbmg.osm.pbf \ $(DIR)/osmosis-DCbmg-osmium.osm.pbf \ $(DIR)/osmium-DCbmg-osmosis.osm.pbf echo "Without metadata:" >$@; \ for i in $^; do \ filename=`basename $$i`; \ crc=`$(OSMIUM_FILEINFO) $$i`; \ echo $$crc $$filename >>$@; \ done; \ echo >>$@ $(DIR)/report: \ $(DIR)/report_default \ $(DIR)/report_granularity \ $(DIR)/report_without_metadata cat $^ >$@ # osmosis from input $(DIR)/osmosis.osm.bz2: $(INPUT) $(DIR) $(OSMOSIS) $(OSMOSIS_READ) $< --write-xml file=$@ $(DIR)/osmosis-DCbMg.osm.pbf: $(INPUT) $(DIR) $(OSMOSIS) $(OSMOSIS_READ) $< --write-pbf file=$@ usedense=true compress=deflate $(DIR)/osmosis-dCbMg.osm.pbf: $(INPUT) $(DIR) $(OSMOSIS) $(OSMOSIS_READ) $< --write-pbf file=$@ usedense=false compress=deflate $(DIR)/osmosis-DcbMg.osm.pbf: $(INPUT) $(DIR) $(OSMOSIS) $(OSMOSIS_READ) $< --write-pbf file=$@ usedense=true compress=none $(DIR)/osmosis-dcbMg.osm.pbf: $(INPUT) $(DIR) $(OSMOSIS) $(OSMOSIS_READ) $< --write-pbf file=$@ usedense=false compress=none $(DIR)/osmosis-DCBMg.osm.pbf: $(INPUT) $(DIR) $(OSMOSIS) $(OSMOSIS_READ) $< --write-pbf file=$@ usedense=true compress=deflate batchlimit=10000 $(DIR)/osmosis-DCbmg.osm.pbf: $(INPUT) $(DIR) $(OSMOSIS) $(OSMOSIS_READ) $< --write-pbf file=$@ usedense=true compress=deflate omitmetadata=true $(DIR)/osmosis-dCbMG.osm.pbf: $(INPUT) $(DIR) $(OSMOSIS) $(OSMOSIS_READ) $< --write-pbf file=$@ usedense=true compress=deflate granularity=10000 # osmium from input $(DIR)/osmium.osm.bz2: $(INPUT) $(DIR) $(OSMIUM) $(OSMIUM_CMD) $< -o $@ $(DIR)/osmium-DCbMg.osm.pbf: $(INPUT) $(DIR) $(OSMIUM) $(OSMIUM_CMD) $< -o $@ -f pbf,pbf_dense_nodes=true,pbf_compression=gzip,pbf_add_metadata=true $(DIR)/osmium-dCbMg.osm.pbf: $(INPUT) $(DIR) $(OSMIUM) $(OSMIUM_CMD) $< -o $@ -f pbf,pbf_dense_nodes=false,pbf_compression=gzip,pbf_add_metadata=true $(DIR)/osmium-DcbMg.osm.pbf: $(INPUT) $(DIR) $(OSMIUM) $(OSMIUM_CMD) $< -o $@ -f pbf,pbf_dense_nodes=true,pbf_compression=none,pbf_add_metadata=true $(DIR)/osmium-dcbMg.osm.pbf: $(INPUT) $(DIR) $(OSMIUM) $(OSMIUM_CMD) $< -o $@ -f pbf,pbf_dense_nodes=false,pbf_compression=none,pbf_add_metadata=true $(DIR)/osmium-DCbmg.osm.pbf: $(INPUT) $(DIR) $(OSMIUM) $(OSMIUM_CMD) $< -o $@ -f pbf,pbf_dense_nodes=true,pbf_compression=gzip,pbf_add_metadata=false # osmium from osmosis output $(DIR)/osmosis-xml-osmium.osm.pbf: $(DIR)/osmosis.osm.bz2 $(DIR) $(OSMIUM) $(OSMIUM_CMD) $< -o $@ $(DIR)/osmosis-DCbMg-osmium.osm.pbf: $(DIR)/osmosis-DCbMg.osm.pbf $(DIR) $(OSMIUM) $(OSMIUM_CMD) $< -o $@ $(DIR)/osmosis-dCbMg-osmium.osm.pbf: $(DIR)/osmosis-dCbMg.osm.pbf $(DIR) $(OSMIUM) $(OSMIUM_CMD) $< -o $@ $(DIR)/osmosis-DcbMg-osmium.osm.pbf: $(DIR)/osmosis-DcbMg.osm.pbf $(DIR) $(OSMIUM) $(OSMIUM_CMD) $< -o $@ $(DIR)/osmosis-dcbMg-osmium.osm.pbf: $(DIR)/osmosis-dcbMg.osm.pbf $(DIR) $(OSMIUM) $(OSMIUM_CMD) $< -o $@ $(DIR)/osmosis-DCbmg-osmium.osm.pbf: $(DIR)/osmosis-DCbmg.osm.pbf $(DIR) $(OSMIUM) $(OSMIUM_CMD) $< -o $@ # osmosis from osmium output $(DIR)/osmium-xml-osmosis.osm.pbf: $(DIR)/osmium.osm.bz2 $(DIR) $(OSMOSIS) $(OSMOSIS) --read-xml $< --write-pbf file=$@ $(DIR)/osmium-DCbMg-osmosis.osm.pbf: $(DIR)/osmium-DCbMg.osm.pbf $(DIR) $(OSMOSIS) $(OSMOSIS) --read-pbf $< --write-pbf file=$@ $(DIR)/osmium-dCbMg-osmosis.osm.pbf: $(DIR)/osmium-dCbMg.osm.pbf $(DIR) $(OSMOSIS) $(OSMOSIS) --read-pbf $< --write-pbf file=$@ $(DIR)/osmium-DcbMg-osmosis.osm.pbf: $(DIR)/osmium-DcbMg.osm.pbf $(DIR) $(OSMOSIS) $(OSMOSIS) --read-pbf $< --write-pbf file=$@ $(DIR)/osmium-dcbMg-osmosis.osm.pbf: $(DIR)/osmium-dcbMg.osm.pbf $(DIR) $(OSMOSIS) $(OSMOSIS) --read-pbf $< --write-pbf file=$@ $(DIR)/osmium-DCbmg-osmosis.osm.pbf: $(DIR)/osmium-DCbmg.osm.pbf $(DIR) $(OSMOSIS) $(OSMOSIS) --read-pbf $< --write-pbf file=$@ omitmetadata=true osmium-tool-1.7.1/test/io/input.osm000066400000000000000000000022321315004223400172420ustar00rootroot00000000000000 osmium-tool-1.7.1/test/merge-changes/000077500000000000000000000000001315004223400174625ustar00rootroot00000000000000osmium-tool-1.7.1/test/merge-changes/CMakeLists.txt000066400000000000000000000012631315004223400222240ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - merge-changes # #----------------------------------------------------------------------------- function(check_merge_changes _name _options _in1 _in2 _output) check_output(merge-changes ${_name} "merge-changes ${_options} --generator=test -f osc merge-changes/${_in1} merge-changes/${_in2}" "merge-changes/${_output}") endfunction() check_merge_changes(merged "" change1.osc change2.osc merged.osc) check_merge_changes(simplified "--simplify" change1.osc change2.osc simplified.osc) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/merge-changes/change1.osc000066400000000000000000000022241315004223400214760ustar00rootroot00000000000000 osmium-tool-1.7.1/test/merge-changes/change2.osc000066400000000000000000000013131315004223400214750ustar00rootroot00000000000000 osmium-tool-1.7.1/test/merge-changes/merged.osc000066400000000000000000000034461315004223400214420ustar00rootroot00000000000000 osmium-tool-1.7.1/test/merge-changes/simplified.osc000066400000000000000000000026151315004223400223210ustar00rootroot00000000000000 osmium-tool-1.7.1/test/merge/000077500000000000000000000000001315004223400160545ustar00rootroot00000000000000osmium-tool-1.7.1/test/merge/CMakeLists.txt000066400000000000000000000021611315004223400206140ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - merge # #----------------------------------------------------------------------------- function(check_merge1 _name _input1 _output) check_output(merge ${_name} "merge --generator=test -f osm merge/${_input1}" "merge/${_output}") endfunction() function(check_merge2 _name _input1 _input2 _output) check_output(merge ${_name} "merge --generator=test -f osm merge/${_input1} merge/${_input2}" "merge/${_output}") endfunction() function(check_merge3 _name _input1 _input2 _input3 _output) check_output(merge ${_name} "merge --generator=test -f osm merge/${_input1} merge/${_input2} merge/${_input3}" "merge/${_output}") endfunction() #----------------------------------------------------------------------------- check_merge1(i1 input1.osm output1.osm) check_merge2(i2f input1.osm input2.osm output2.osm) check_merge2(i2r input2.osm input1.osm output2.osm) check_merge3(i3f input1.osm input2.osm input3.osm output3.osm) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/merge/input1.osm000066400000000000000000000023131315004223400200130ustar00rootroot00000000000000 osmium-tool-1.7.1/test/merge/input2.osm000066400000000000000000000021321315004223400200130ustar00rootroot00000000000000 osmium-tool-1.7.1/test/merge/input3.osm000066400000000000000000000015011315004223400200130ustar00rootroot00000000000000 osmium-tool-1.7.1/test/merge/output1.osm000066400000000000000000000022701315004223400202160ustar00rootroot00000000000000 osmium-tool-1.7.1/test/merge/output2.osm000066400000000000000000000040731315004223400202220ustar00rootroot00000000000000 osmium-tool-1.7.1/test/merge/output3.osm000066400000000000000000000054261315004223400202260ustar00rootroot00000000000000 osmium-tool-1.7.1/test/misc/000077500000000000000000000000001315004223400157105ustar00rootroot00000000000000osmium-tool-1.7.1/test/misc/CMakeLists.txt000066400000000000000000000010201315004223400204410ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - misc # #----------------------------------------------------------------------------- do_test(version1 "osmium --version" "^osmium version ${OSMIUM_VERSION}") do_test(version2 "osmium version" "^osmium version ${OSMIUM_VERSION}") do_test(unknown_command "osmium x" "^Unknown command or option 'x'. Try 'osmium help'.\n") #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/order/000077500000000000000000000000001315004223400160705ustar00rootroot00000000000000osmium-tool-1.7.1/test/order/fail-order-n.osm000066400000000000000000000006711315004223400210730ustar00rootroot00000000000000 osmium-tool-1.7.1/test/order/fail-order-r.osm000066400000000000000000000021431315004223400210730ustar00rootroot00000000000000 osmium-tool-1.7.1/test/order/fail-order-rw.osm000066400000000000000000000016341315004223400212660ustar00rootroot00000000000000 osmium-tool-1.7.1/test/order/fail-order-w.osm000066400000000000000000000013251315004223400211010ustar00rootroot00000000000000 osmium-tool-1.7.1/test/order/fail-order-wn.osm000066400000000000000000000013251315004223400212570ustar00rootroot00000000000000 osmium-tool-1.7.1/test/renumber/000077500000000000000000000000001315004223400165745ustar00rootroot00000000000000osmium-tool-1.7.1/test/renumber/CMakeLists.txt000066400000000000000000000047671315004223400213520ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - renumber # #----------------------------------------------------------------------------- function(check_renumber _name _input _output) check_output(renumber ${_name} "renumber --generator=test -f osm renumber/${_input}" "renumber/${_output}") endfunction() function(check_renumber_nodes _name _input _output) check_output(renumber ${_name} "renumber --generator=test -t node -f osm renumber/${_input}" "renumber/${_output}") endfunction() function(check_renumber2 _name _in1 _in2 _out) set(_idxdir "${PROJECT_BINARY_DIR}/test/renumber/index/${_name}") if(WIN32) set(_devnull "nul") else() set(_devnull "/dev/null") endif() check_output2(renumber ${_name} ${_idxdir} "renumber --index-directory=${_idxdir} --generator=test -f osm --overwrite -o ${_devnull} renumber/${_in1}" "renumber --index-directory=${_idxdir} --generator=test -f osc renumber/${_in2}" "renumber/${_out}" ) endfunction() check_renumber(sorted input-sorted.osm output-sorted.osm) check_renumber_nodes(nodes-sorted input-sorted.osm output-sorted-n.osm) check_renumber2(change input-sorted.osm input-change.osc output-change.osc) check_renumber2(change-norel input-norel.osm input-change.osc output-norel-change.osc) #----------------------------------------------------------------------------- # input data not ordered properly add_test(NAME renumber-fail-order-n COMMAND osmium renumber ${CMAKE_SOURCE_DIR}/test/order/fail-order-n.osm -f osm) set_tests_properties(renumber-fail-order-n PROPERTIES WILL_FAIL true) add_test(NAME renumber-fail-order-w COMMAND osmium renumber ${CMAKE_SOURCE_DIR}/test/order/fail-order-w.osm -f osm) set_tests_properties(renumber-fail-order-w PROPERTIES WILL_FAIL true) add_test(NAME renumber-fail-order-r COMMAND osmium renumber ${CMAKE_SOURCE_DIR}/test/order/fail-order-r.osm -f osm) set_tests_properties(renumber-fail-order-r PROPERTIES WILL_FAIL true) add_test(NAME renumber-fail-order-wn COMMAND osmium renumber ${CMAKE_SOURCE_DIR}/test/order/fail-order-wn.osm -f osm) set_tests_properties(renumber-fail-order-wn PROPERTIES WILL_FAIL true) add_test(NAME renumber-fail-order-rw COMMAND osmium renumber ${CMAKE_SOURCE_DIR}/test/order/fail-order-rw.osm -f osm) set_tests_properties(renumber-fail-order-rw PROPERTIES WILL_FAIL true) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/renumber/input-change.osc000066400000000000000000000013131315004223400216620ustar00rootroot00000000000000 osmium-tool-1.7.1/test/renumber/input-norel.osm000066400000000000000000000016211315004223400215700ustar00rootroot00000000000000 osmium-tool-1.7.1/test/renumber/input-sorted.osm000066400000000000000000000022111315004223400217450ustar00rootroot00000000000000 osmium-tool-1.7.1/test/renumber/output-change.osc000066400000000000000000000013011315004223400220600ustar00rootroot00000000000000 osmium-tool-1.7.1/test/renumber/output-norel-change.osc000066400000000000000000000013011315004223400231750ustar00rootroot00000000000000 osmium-tool-1.7.1/test/renumber/output-sorted-n.osm000066400000000000000000000021701315004223400224050ustar00rootroot00000000000000 osmium-tool-1.7.1/test/renumber/output-sorted.osm000066400000000000000000000021641315004223400221550ustar00rootroot00000000000000 osmium-tool-1.7.1/test/sort/000077500000000000000000000000001315004223400157445ustar00rootroot00000000000000osmium-tool-1.7.1/test/sort/CMakeLists.txt000066400000000000000000000020241315004223400205020ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - sort # #----------------------------------------------------------------------------- function(check_sort2 _name _in1 _in2 _output) check_output(sort ${_name} "sort --generator=test -f osm sort/${_in1} sort/${_in2}" "sort/${_output}") endfunction() function(check_sort1 _name _input _output _format) check_output(sort ${_name} "sort --generator=test -f ${_format} sort/${_input}" "sort/${_output}") endfunction() #----------------------------------------------------------------------------- check_sort2(simple input-simple1.osm input-simple2.osm output-simple.osm) check_sort2(bounds input-bounds1.osm input-bounds2.osm output-bounds.osm) check_sort2(history input-history1.osm input-history2.osm output-history.osm) check_sort1(neg input-neg.osm output-neg.osm osm) check_sort1(change input-change.osc output-change.osc osc) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/sort/input-bounds1.osm000066400000000000000000000016071315004223400212000ustar00rootroot00000000000000 osmium-tool-1.7.1/test/sort/input-bounds2.osm000066400000000000000000000007551315004223400212040ustar00rootroot00000000000000 osmium-tool-1.7.1/test/sort/input-change.osc000066400000000000000000000013131315004223400210320ustar00rootroot00000000000000 osmium-tool-1.7.1/test/sort/input-history1.osm000066400000000000000000000013231315004223400214020ustar00rootroot00000000000000 osmium-tool-1.7.1/test/sort/input-history2.osm000066400000000000000000000010521315004223400214020ustar00rootroot00000000000000 osmium-tool-1.7.1/test/sort/input-neg.osm000066400000000000000000000025471315004223400204020ustar00rootroot00000000000000 osmium-tool-1.7.1/test/sort/input-simple1.osm000066400000000000000000000014551315004223400212000ustar00rootroot00000000000000 osmium-tool-1.7.1/test/sort/input-simple2.osm000066400000000000000000000006231315004223400211750ustar00rootroot00000000000000 osmium-tool-1.7.1/test/sort/output-bounds.osm000066400000000000000000000022011315004223400213070ustar00rootroot00000000000000 osmium-tool-1.7.1/test/sort/output-change.osc000066400000000000000000000013071315004223400212360ustar00rootroot00000000000000 osmium-tool-1.7.1/test/sort/output-history.osm000066400000000000000000000022041315004223400215210ustar00rootroot00000000000000 osmium-tool-1.7.1/test/sort/output-neg.osm000066400000000000000000000025241315004223400205760ustar00rootroot00000000000000 osmium-tool-1.7.1/test/sort/output-simple.osm000066400000000000000000000021071315004223400213130ustar00rootroot00000000000000 osmium-tool-1.7.1/test/tags-filter/000077500000000000000000000000001315004223400171765ustar00rootroot00000000000000osmium-tool-1.7.1/test/tags-filter/CMakeLists.txt000066400000000000000000000024051315004223400217370ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - tags-filter # #----------------------------------------------------------------------------- function(check_tags_filter_R _name _input _expressions _output) check_output(tags-filter ${_name} "tags-filter --generator=test -f osm -R tags-filter/${_input} ${_expressions}" "tags-filter/${_output}") endfunction() function(check_tags_filter_i _name _input _expressions _output) check_output(tags-filter ${_name} "tags-filter --generator=test -f osm -i -R tags-filter/${_input} ${_expressions}" "tags-filter/${_output}") endfunction() function(check_tags_filter _name _input _expressions _output) check_output(tags-filter ${_name} "tags-filter --generator=test -f osm tags-filter/${_input} ${_expressions}" "tags-filter/${_output}") endfunction() check_tags_filter_R(node input.osm n/amenity output-amenity.osm) check_tags_filter_R(highway input.osm w/highway output-highway.osm) check_tags_filter_R(note input.osm note output-note.osm) check_tags_filter_i(note-i input.osm note output-no-note.osm) check_tags_filter(highway-r input.osm w/highway output-highway-r.osm) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/tags-filter/input.osm000066400000000000000000000027531315004223400210640ustar00rootroot00000000000000 osmium-tool-1.7.1/test/tags-filter/output-amenity.osm000066400000000000000000000003611315004223400227220ustar00rootroot00000000000000 osmium-tool-1.7.1/test/tags-filter/output-highway-r.osm000066400000000000000000000016551315004223400231620ustar00rootroot00000000000000 osmium-tool-1.7.1/test/tags-filter/output-highway.osm000066400000000000000000000007511315004223400227170ustar00rootroot00000000000000 osmium-tool-1.7.1/test/tags-filter/output-no-note.osm000066400000000000000000000020361315004223400226340ustar00rootroot00000000000000 osmium-tool-1.7.1/test/tags-filter/output-note.osm000066400000000000000000000010151315004223400222160ustar00rootroot00000000000000 osmium-tool-1.7.1/test/time-filter/000077500000000000000000000000001315004223400171765ustar00rootroot00000000000000osmium-tool-1.7.1/test/time-filter/CMakeLists.txt000066400000000000000000000027721315004223400217460ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - time-filter # #----------------------------------------------------------------------------- function(check_time_filter _name _type _from _to _output) check_output(time-filter ${_name} "time-filter --generator=test -f ${_type} time-filter/input.osh ${_from} ${_to}" "time-filter/output-${_output}.${_type}") endfunction() #----------------------------------------------------------------------------- check_time_filter(last osm "" "" last) check_time_filter(ts1 osm 2015-01-01T01:00:00Z "" ts1) check_time_filter(ts1a osm 2015-01-01T01:01:00Z "" ts1) check_time_filter(ts2 osm 2015-01-01T02:00:00Z "" ts2) check_time_filter(ts2a osm 2015-01-01T02:01:00Z "" ts2) check_time_filter(ts3 osm 2015-01-01T03:00:00Z "" ts3) check_time_filter(ts3a osm 2015-01-01T03:01:00Z "" ts3) check_time_filter(range-0-5 osh 2015-01-01T00:00:00Z 2015-01-01T05:00:00Z range-0-5) check_time_filter(range-1-2 osh 2015-01-01T01:00:00Z 2015-01-01T02:00:00Z range-1-2) check_time_filter(range-1a-2a osh 2015-01-01T01:01:00Z 2015-01-01T02:01:00Z range-1a-2a) check_time_filter(range-2-3 osh 2015-01-01T02:00:00Z 2015-01-01T03:00:00Z range-2-3) check_time_filter(range-2-3a osh 2015-01-01T02:00:00Z 2015-01-01T03:01:00Z range-2-3a) check_time_filter(range-2-4 osh 2015-01-01T02:00:00Z 2015-01-01T04:00:00Z range-2-4) #----------------------------------------------------------------------------- osmium-tool-1.7.1/test/time-filter/input.osh000066400000000000000000000025641315004223400210570ustar00rootroot00000000000000 osmium-tool-1.7.1/test/time-filter/output-last.osm000066400000000000000000000004631315004223400222220ustar00rootroot00000000000000 osmium-tool-1.7.1/test/time-filter/output-range-0-5.osh000066400000000000000000000024721315004223400226470ustar00rootroot00000000000000 osmium-tool-1.7.1/test/time-filter/output-range-1-2.osh000066400000000000000000000007201315004223400226370ustar00rootroot00000000000000 osmium-tool-1.7.1/test/time-filter/output-range-1a-2a.osh000066400000000000000000000017141315004223400231450ustar00rootroot00000000000000 osmium-tool-1.7.1/test/time-filter/output-range-2-3.osh000066400000000000000000000011171315004223400226420ustar00rootroot00000000000000 osmium-tool-1.7.1/test/time-filter/output-range-2-3a.osh000066400000000000000000000015151315004223400230050ustar00rootroot00000000000000 osmium-tool-1.7.1/test/time-filter/output-range-2-4.osh000066400000000000000000000015151315004223400226450ustar00rootroot00000000000000 osmium-tool-1.7.1/test/time-filter/output-ts1.osm000066400000000000000000000006431315004223400217660ustar00rootroot00000000000000 osmium-tool-1.7.1/test/time-filter/output-ts2.osm000066400000000000000000000006431315004223400217670ustar00rootroot00000000000000 osmium-tool-1.7.1/test/time-filter/output-ts3.osm000066400000000000000000000006431315004223400217700ustar00rootroot00000000000000 osmium-tool-1.7.1/test/time-filter/test_setup.cpp000066400000000000000000000003521315004223400221010ustar00rootroot00000000000000 #include "test.hpp" // IWYU pragma: keep #include "command_time_filter.hpp" TEST_CASE("time-filter") { CommandTimeFilter cmd; SECTION("no parameters") { REQUIRE_THROWS_AS(cmd.setup({}), argument_error); } } osmium-tool-1.7.1/test/unit_tests.cpp000066400000000000000000000001041315004223400176550ustar00rootroot00000000000000#define CATCH_CONFIG_MAIN #include "catch.hpp" // IWYU pragma: keep osmium-tool-1.7.1/test/util/000077500000000000000000000000001315004223400157325ustar00rootroot00000000000000osmium-tool-1.7.1/test/util/test_unit.cpp000066400000000000000000000115241315004223400204570ustar00rootroot00000000000000 #include "test.hpp" // IWYU pragma: keep #include "util.hpp" TEST_CASE("Get suffix from filename") { REQUIRE(get_filename_suffix("foo.bar") == "bar"); } TEST_CASE("Get suffixes from filename") { REQUIRE(get_filename_suffix("foo.bar.baz") == "bar.baz"); } TEST_CASE("Get suffixes from file path") { REQUIRE(get_filename_suffix("/usr/local/foo.bar.baz") == "bar.baz"); } TEST_CASE("Get suffixes from relative path") { REQUIRE(get_filename_suffix("../somewhere/foo.bar.baz") == "bar.baz"); } TEST_CASE("Get suffixes from path with dots in the middle") { REQUIRE(get_filename_suffix("anything/../somewhere/foo.bar.baz") == "bar.baz"); } TEST_CASE("Get object types") { REQUIRE(get_types("") == osmium::osm_entity_bits::nothing); REQUIRE(get_types("n") == osmium::osm_entity_bits::node); REQUIRE(get_types("w") == osmium::osm_entity_bits::way); REQUIRE(get_types("r") == osmium::osm_entity_bits::relation); REQUIRE(get_types("nw") == (osmium::osm_entity_bits::node | osmium::osm_entity_bits::way)); REQUIRE(get_types("rw") == (osmium::osm_entity_bits::way | osmium::osm_entity_bits::relation)); REQUIRE_THROWS_AS(get_types("x"), argument_error); REQUIRE_THROWS_AS(get_types("nwx"), argument_error); } static void test_filter(const std::string& expression, osmium::osm_entity_bits::type entities, const char* filter) { const auto p = get_filter_expression(expression); REQUIRE(p.first == entities); REQUIRE(p.second == filter); } TEST_CASE("Get tags filter expression") { test_filter("highway", osmium::osm_entity_bits::nwr, "highway"); test_filter("/highway", osmium::osm_entity_bits::nwr, "highway"); test_filter("n/highway", osmium::osm_entity_bits::node, "highway"); test_filter("w/highway", osmium::osm_entity_bits::way, "highway"); test_filter("r/highway", osmium::osm_entity_bits::relation, "highway"); test_filter("nw/highway", osmium::osm_entity_bits::node | osmium::osm_entity_bits::way, "highway"); test_filter("n/highway/foo", osmium::osm_entity_bits::node, "highway/foo"); REQUIRE_THROWS_AS(get_filter_expression("highway/foo"), argument_error); } void test_strip_whitespace(const char* in, const char* out) { std::string str{in}; strip_whitespace(str); REQUIRE(str == out); } TEST_CASE("strip whitespace") { test_strip_whitespace("foo", "foo"); test_strip_whitespace(" foo", "foo"); test_strip_whitespace("foo ", "foo"); test_strip_whitespace(" foo ", "foo"); test_strip_whitespace(" foo ", "foo"); test_strip_whitespace("f o o", "f o o"); } void test_string_matcher(const char* string, const char* print_out) { std::stringstream ss; ss << get_string_matcher(string); REQUIRE(ss.str() == print_out); } TEST_CASE("get_string_matcher") { test_string_matcher("foo", "equal[foo]"); test_string_matcher("", "equal[]"); test_string_matcher("foo*", "prefix[foo]"); test_string_matcher(" foo* ", "prefix[foo]"); test_string_matcher("*foo", "substring[foo]"); test_string_matcher("*foo*", "substring[foo]"); test_string_matcher(" *foo* ", "substring[foo]"); test_string_matcher("*", "always_true"); test_string_matcher(" * ", "always_true"); test_string_matcher("f*oo", "equal[f*oo]"); test_string_matcher("foo,bar", "list[[foo][bar]]"); test_string_matcher("foo,bar*,baz", "list[[foo][bar*][baz]]"); test_string_matcher("*foo,bar", "substring[foo,bar]"); test_string_matcher("foo ", "equal[foo]"); test_string_matcher(" foo", "equal[foo]"); test_string_matcher(" foo ", "equal[foo]"); test_string_matcher("foo ", "equal[foo]"); test_string_matcher(" foo", "equal[foo]"); test_string_matcher(" foo ", "equal[foo]"); test_string_matcher("foo, bar, baz", "list[[foo][bar][baz]]"); test_string_matcher(" foo, bar ,baz ", "list[[foo][bar][baz]]"); } bool test_tag_matcher(const char* expression, const char* key, const char* value) { const auto matcher = get_tag_matcher(expression); return matcher(key, value); } TEST_CASE("get_tag_matcher") { REQUIRE(test_tag_matcher("foo", "foo", "bar")); REQUIRE(test_tag_matcher("foo=bar", "foo", "bar")); REQUIRE(test_tag_matcher("foo!=bar", "foo", "baz")); REQUIRE_FALSE(test_tag_matcher("foo!=bar", "foo", "bar")); REQUIRE(test_tag_matcher("highway=primary,secondary", "highway", "primary")); REQUIRE(test_tag_matcher("highway=primary,secondary", "highway", "secondary")); REQUIRE_FALSE(test_tag_matcher("highway=primary,secondary", "highway", "residential")); REQUIRE(test_tag_matcher("landuse,natural", "landuse", "forest")); REQUIRE(test_tag_matcher("landuse,natural", "natural", "wood")); REQUIRE_FALSE(test_tag_matcher("landuse,natural", "highway", "motorway")); REQUIRE(test_tag_matcher("addr:*", "addr:city", "Berlin")); REQUIRE_FALSE(test_tag_matcher("addr:*", "addr", "Berlin")); } osmium-tool-1.7.1/zsh_completion/000077500000000000000000000000001315004223400170335ustar00rootroot00000000000000osmium-tool-1.7.1/zsh_completion/_osmium000066400000000000000000000516371315004223400204420ustar00rootroot00000000000000#compdef osmium # # ZSH completion for Osmium tool. # # To test this file: # 1) Comment out last line # 2) Call: . ./_osmium # 3) Call: compdef _osmium osmium # # To read more about what is happening here: # zshcompsys(1) # http://bewatermyfriend.org/p/2012/003/ # http://zsh.sourceforge.net/Guide/zshguide06.html # osmium_file_glob="'*.(osm|osh|osc|o5m|o5c|pbf|osm.pbf) *.(osm|osh|osc|o5m|o5c).(bz2|gz)'" polygon_file_glob="'*.json *.geojson *.poly *.(osm|osh|osc|o5m|o5c|pbf|osm.pbf) *.(osm|osh|osc|o5m|o5c).(bz2|gz)'" _osmium() { local -a osmium_commands osmium_commands=(add-locations-to-ways apply-changes cat diff changeset-filter check-refs derive-changes export extract fileinfo getid help merge merge-changes renumber show sort tags-filter time-filter) if (( CURRENT > 2 )); then # Remember the subcommand name local cmd=${words[2]} # Set the context for the subcommand. curcontext="${curcontext%:*:*}:osmium-$cmd" # Narrow the range of words we are looking at to exclude `osmium' (( CURRENT-- )) shift words # Run the completion for the subcommand _osmium-$cmd else _describe -t osmium-commands 'osmium subcommand' osmium_commands fi } _osmium-common-options() { echo '(--help)-h[show usage help]' echo '(-h)--help[show usage help]' echo '(--verbose)-v[set verbose mode]' echo '(-v)--verbose[set verbose mode]' } _osmium-single-input-options() { echo '(--input-format)-F[format of input OSM file]:OSM file format:_osmium_input_file_formats' echo '(-F)--input-format[format of input OSM file]:OSM file format:_osmium_input_file_formats' echo "1:input OSM files:_files -g ${osmium_file_glob}" } _osmium-multiple-inputs-options() { echo '(--input-format)-F[format of input OSM files]:OSM file format:_osmium_input_file_formats' echo '(-F)--input-format[format of input OSM files]:OSM file format:_osmium_input_file_formats' echo "*:input OSM files:_files -g ${osmium_file_glob}" } _osmium-output-options() { echo '--fsync[call fsync after writing output file(s)]' echo '--generator[generator setting for output file header]:' echo "*--output-header[add option to output header]:" echo "(--output)-o[output file name]:output OSM file:_files -g ${osmium_file_glob}" echo "(-o)--output[output file name]:output OSM file:_files -g ${osmium_file_glob}" echo '(--overwrite)-O[allow overwriting of existing output file]' echo '(-O)--overwrite[allow overwriting of existing output file]' } _osmium-output-format-options() { echo '(--output-format)-f[format of output OSM file]:OSM file format:_osmium_output_file_formats' echo '(-f)--output-format[format of output OSM file]:OSM file format:_osmium_output_file_formats' } _osmium-diff-output-format-options() { echo '(--output-format)-f[format of output file]:OSM file format:_osmium_diff_file_formats' echo '(-f)--output-format[format of output file]:OSM file format:_osmium_diff_file_formats' } _osmium-add-locations-to-ways() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-multiple-inputs-options)"} \ ${(f)"$(_osmium-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} \ '(--index-type -I --show-index-types)-i[set index type]:index types:_osmium_index_types' \ '(-i -I --show-index-types)--index-type[set index type]:index types:_osmium_index_types' \ '(--show-index-types -i --index-type -n --keep-untagged-nodes)-I[show available index types]' \ '(-I -i --index-type -n --keep-untagged-nodes)--show-index-types[show available index types]' \ '(--keep-untagged-nodes -I --show-index-types)-n[keep untagged nodes in output]' \ '(-n -I --show-index-types)--keep-untagged-nodes[keep untagged nodes in output]' \ '(--progress)--no-progress[disable progress bar]' \ '(--no-progress)--progress[enable progress bar]' } _osmium-apply-changes() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-multiple-inputs-options)"} \ ${(f)"$(_osmium-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} \ '--change-file-format[Format of the change file(s)]' \ '--locations-on-ways[update OSM file with locations on ways]' \ '(--with-history)-H[update OSM history file]' \ '(-H)--with-history[update OSM history file]' } _osmium-cat() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-multiple-inputs-options)"} \ ${(f)"$(_osmium-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} \ '*-t[read only objects of given output types]:OSM entity type:_osmium_entity_type' \ '*--object-type[read only objects of given output types]:OSM entity type:_osmium_entity_type' \ '(--progress)--no-progress[disable progress bar]' \ '(--no-progress)--progress[enable progress bar]' } _osmium-changeset-filter() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-single-input-options)"} \ ${(f)"$(_osmium-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} \ '(--with-discussions)-d[changesets with discussions]' \ '(-d)--with-discussions[changesets with discussions]' \ '(--without-discussions)-D[changesets without discussions]' \ '(-D)--without-discussions[changesets without discussions]' \ '(--with-changes)-c[changesets with changes]' \ '(-c)--with-changes[changesets with changes]' \ '(--without-changes)-C[changesets without changes]' \ '(-C)--without-changes[changesets without changes]' \ '--open[open changesets]' \ '--closed[closed changesets]' \ '(--user)-u[changesets by user]' \ '(-u)--user[changesets by user]' \ '(--uid)-U[changesets by user id]' \ '(-U)--uid[changesets by user id]' \ '-a[changesets closed after]:timestamp:' \ '--after[changesets closed after]:timestamp:' \ '-b[changesets opened before]:timestamp:' \ '--before[changesets opened before]:timestamp:' \ '(--bbox)-B[bounding box]:changesets in bounding box (format\: LEFT,BOTTOM,RIGHT,TOP):' \ '(-B)--bbox[bounding box]:changesets in bounding box (format\: LEFT,BOTTOM,RIGHT,TOP):' \ '(--progress)--no-progress[disable progress bar]' \ '(--no-progress)--progress[enable progress bar]' } _osmium-check-refs() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-single-input-options)"} \ '(--show-ids)-i[show ids of missing objects]' \ '(-i)--show-ids[show ids of missing objects]' \ '(--check-relations)-r[also check referential integrity of relations]' \ '(-r)--check-relations[also check referential integrity of relations]' \ '(--progress)--no-progress[disable progress bar]' \ '(--no-progress)--progress[enable progress bar]' } _osmium-derive-changes() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-multiple-inputs-options)"} \ ${(f)"$(_osmium-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} \ '--increment-version[increment version of deleted objects]' \ '--keep-details[keep details of deleted objects]' \ '--update-timestamp[update timestamp of deleted objects]' } _osmium-diff() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-multiple-inputs-options)"} \ ${(f)"$(_osmium-diff-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} \ '(--quiet)-q[report only when files differ]' \ '(-q)--quiet[report only when files differ]' \ '(--suppress-common)-c[suppress common objects]' \ '(-c)--suppress-common[suppress common objects]' \ '(--summary)-s[Show summary on STDERR]' \ '(-s)--summary[Show summary on STDERR]' \ '*-t[read only objects of given output types]:OSM entity type:_osmium_object_type' \ '*--object-type[read only objects of given output types]:OSM entity type:_osmium_object_type' } _osmium-export() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-single-input-options)"} \ '--fsync[call fsync after writing output file(s)]' \ '(--output)-o[output file name]:output OSM file:_files -g "*.json *.geojson *.jsonseq *.geojsonseq"' \ '(-o)--output[output file name]:output OSM file:_files -g "*.json *.geojson *.jsonseq *.geojsonseq"' \ '(--overwrite)-O[allow overwriting of existing output file]' \ '(-O)--overwrite[allow overwriting of existing output file]' \ '(--output-format)-f[format of output file]:file format:_export_file_formats' \ '(-f)--output-format[format of output file]:file format:_export_file_formats' \ '(--config)-c[config file]:config file:_files -f "*.json"' \ '(-c)--config[config file]:config file:_files -f "*.json"' \ '(--show-errors)-e[output errors to stderr]' \ '(-e)--show-errors[output errors to stderr]' \ '(--stop-on-error)-E[stop on first geometry error]' \ '(-E)--stop-on-error[stop on first geometry error]' \ '(--index-type -I --show-index-types)-i[set index type]:index types:_osmium_export_index_types' \ '(-i -I --show-index-types)--index-type[set index type]:index types:_osmium_export_index_types' \ '(--help -h --verbose -v --input-format -F --fsync --output -o --overwrite -O --output-format -f --config -c --show-errors -e --stop-on-error -E --index-type -i --keep-untagged -n --omit-rs -r --add-unique-id -u --show-index-types)-I[show a list of available index types]' \ '(--help -h --verbose -v --input-format -F --fsync --output -o --overwrite -O --output-format -f --config -c --show-errors -e --stop-on-error -E --index-type -i --keep-untagged -n --omit-rs -r --add-unique-id -u -I)--show-index-types[show a list of available index types]' \ '(--keep-untagged)-n[keep untagged features]' \ '(-n)--keep-untagged[keep untagged features]' \ '(--omit-rs)-r[omit record separator when using geojsonseq format]' \ '(-r)--omit-rs[omit record separator when using geojsonseq format]' \ '(--add-unique-id)-u[add unique id]:unique id format:_export_id_type' \ '(-u)--add-unique-id[add unique id]:unique id format:_export_id_type' } _osmium-extract() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-single-input-options)"} \ ${(f)"$(_osmium-output-options)"} \ ${(f)"$(_osmium-output-format-options)"} \ '(--config -c --directory -d --polygon -p --bbox)-b[bounding box]:bounding box (format\: LEFT,BOTTOM,RIGHT,TOP):' \ '(--config -c --directory -d --polygon -p -b)--bbox[bounding box]:bounding box (format\: LEFT,BOTTOM,RIGHT,TOP):' \ '(--bbox -b --polygon -p --output -o --output-format -f --config)-c[specify config file]:config file:_files -g "*.json"' \ '(--bbox -b --polygon -p --output -o --output-format -f -c)--config[specify config file]:config file:_files -g "*.json"' \ '(--output -o --output-format -f --bbox -b --polygon -p --directory)-d[output directory]:directory:_path_files -/' \ '(--output -o --output-format -f --bbox -b --polygon -p -d)--directory[output directory]:directory:_path_files -/' \ "(--config -c --directory -d --bbox -b --polygon)-p[polygon file]:polygon file:_files -g ${polygon_file_glob}" \ "(--config -c --directory -d --bbox -b -p)--polygon[polygon file]:polygon file:_files -g ${polygon_file_glob}" \ '(--strategy)-s[use strategy for computing extract]:extract strategy:_osmium_extract_strategy' \ '(-s)--strategy[use strategy for computing extract]:extract strategy:_osmium_extract_strategy' \ '*-S[set strategy option]:' \ '*--option[set strategy option]:' \ '(--with-history)-H[input and output files are OSM history files]' \ '(-H)--with-history[input and output files are OSM history files]' } _osmium-fileinfo() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-single-input-options)"} \ '(--show-variables -G --extended)-e[show extended info (reads entire file)]' \ '(--show-variables -G -e)--extended[show extended info (reads entire file)]' \ '(--show-variables -G --json -j --get)-g[get value for one variable]:variable:_osmium_fileinfo_variables' \ '(--show-variables -G --json -j -g)--get[get value for one variable]:variable:_osmium_fileinfo_variables' \ '(--get -g --json)-j[output variables in JSON format]' \ '(--get -g -j)--json[output variables in JSON format]' \ '(--get -g --json -j --extended -e --show-variables)-G[show a list of all variable names]' \ '(--get -g --json -j --extended -e -G)--show-variables[show a list of all variable names]' \ '(--progress)--no-progress[disable progress bar]' \ '(--no-progress)--progress[enable progress bar]' } _osmium-getid() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-single-input-options)"} \ ${(f)"$(_osmium-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} \ '--default-type[default item type]' \ '-i[read OSM IDs from text file]' \ '--id-file[read OSM IDs from text file]' \ '-I[read OSM IDs from OSM file]' \ '--id-osm-file[read OSM IDs from OSM file]' \ '(--add-referenced)-r[recursively add referenced objects]' \ '(-r)--add-referenced[recursively add referenced objects]' \ '(--with-history)-H[make it work with history files]' \ '(-H)--with-history[make it work with history files]' \ '(--progress)--no-progress[disable progress bar]' \ '(--no-progress)--progress[enable progress bar]' \ "*:IDs (format\: [nwr]ID):" } _osmium-merge() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-multiple-inputs-options)"} \ ${(f)"$(_osmium-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} } _osmium-merge-changes() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-multiple-inputs-options)"} \ ${(f)"$(_osmium-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} \ '(--simplify)-s[only write last version of any object]' \ '(-s)--simplify[only write last version of any object]' } _osmium-renumber() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-single-input-options)"} \ ${(f)"$(_osmium-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} \ '(--index-directory)-i[read/write index files in this directory]:directory:_path_files -/' \ '(-i)--index-directory[read/write index files in this directory]:directory:_path_files -/' \ '(--progress)--no-progress[disable progress bar]' \ '(--no-progress)--progress[enable progress bar]' \ '*-t[renumber only objects of given output types]:OSM entity type:_osmium_object_type' \ '*--object-type[renumber only objects of given output types]:OSM entity type:_osmium_object_type' } _osmium-show() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-single-input-options)"} \ '(--output-format --format-debug -d --format-opl -o --format-xml -x)-f[format of output OSM file]:OSM file format:_osmium_output_file_formats' \ '(-f --format-debug -d --format-opl -o --format-xml -x)--output-format[format of output OSM file]:OSM file format:_osmium_output_file_formats' \ '(--output-format -f -d --format-opl -o --format-xml -x)--format-debug[set format of output OSM file to debug]' \ '(--output-format -f --format-debug --format-opl -o --format-xml -x)-d[set format of output OSM file to debug]' \ '(--output-format -f --format-debug -d -o --format-xml -x)--format-opl[set format of output OSM file to OPL]' \ '(--output-format -f --format-debug -d --format-opl --format-xml -x)-o[set format of output OSM file to OPL]' \ '(--output-format -f --format-debug -d --format-opl -o -x)--format-xml[set format of output OSM file to XML]' \ '(--output-format -f --format-debug -d --format-opl -o --format-xml)-x[set format of output OSM file to XML]' \ '--no-pager[disable pager]' \ '*-t[read only objects of given output types]:OSM entity type:_osmium_entity_type' \ '*--object-type[read only objects of given output types]:OSM entity type:_osmium_entity_type' } _osmium-sort() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-multiple-inputs-options)"} \ ${(f)"$(_osmium-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} } _osmium-tags-filter() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-single-input-options)"} \ ${(f)"$(_osmium-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} \ '(--expressions)-e[read filter expressions from file]:filter expressions file:_files' \ '(-e)--expressions[read filter expressions from file]:filter expressions file:_files' \ '(--invert-match)-i[invert the sense of matching, exclude objects with matching tags]' \ '(-i)--invert-match[invert the sense of matching, exclude objects with matching tags]' \ '(--omit-referenced)-R[omit referenced objects]' \ '(-R)--omit-referenced[omit referenced objects]' \ "*:Filter expressions (format\: [nwr]*/key=[value]):" } _osmium-time-filter() { _arguments : \ ${(f)"$(_osmium-common-options)"} \ ${(f)"$(_osmium-single-input-options)"} \ ${(f)"$(_osmium-output-format-options)"} \ ${(f)"$(_osmium-output-options)"} \ "2::start time (format\: yyyy-mm-ddThh\:mm\:ssZ):" \ "3::end time (format\: yyyy-mm-ddThh\:mm\:ssZ):" } _osmium_input_file_formats() { _values 'OSM input file formats' \ 'osm[XML data format]' \ 'osm.gz[XML data format (compressed with gzip)]' \ 'osm.bz2[XML data format (compressed with bzip2)]' \ 'osh[XML history format]' \ 'osh.gz[XML history format (compressed with gzip)]' \ 'osh.bz2[XML history format (compressed with bzip2)]' \ 'osc[XML change format]' \ 'osc.gz[XML change format (compressed with gzip)]' \ 'osc.bz2[XML change format (compressed with bzip2)]' \ 'o5m[o5m data format]' \ 'o5c[o5c change format]' \ 'pbf[PBF format]' } _osmium_output_file_formats() { _values 'OSM output file formats' \ 'debug[Debug data format]' \ 'debug.gz[Debug data format (compressed with gzip)]' \ 'debug.bz2[Debug data format (compressed with bzip2)]' \ 'opl[OPL data format]' \ 'opl.gz[OPL data format (compressed with gzip)]' \ 'opl.bz2[OPL data format (compressed with bzip2)]' \ 'osm[XML data format]' \ 'osm.gz[XML data format (compressed with gzip)]' \ 'osm.bz2[XML data format (compressed with bzip2)]' \ 'osh[XML history format]' \ 'osh.gz[XML history format (compressed with gzip)]' \ 'osh.bz2[XML history format (compressed with bzip2)]' \ 'osc[XML change format]' \ 'osc.gz[XML change format (compressed with gzip)]' \ 'osc.bz2[XML change format (compressed with bzip2)]' \ 'pbf[PBF format]' } _osmium_diff_file_formats() { _values 'Diff file formats' \ 'opl[One object per line]' \ 'debug[Debug format]' \ 'debug,color[Debug format with color]' \ 'compact[Compact format]' } _osmium_object_type() { _values 'OSM object type' \ 'node' \ 'way' \ 'relation' } _osmium_entity_type() { _values 'OSM entity type' \ 'node' \ 'way' \ 'relation' \ 'changeset' } _export_file_formats() { _values 'export file formats' \ 'json[GeoJSON format]' \ 'geojson[GeoJSON format]' \ 'jsonseq[GeoJSON Text Sequence format]' \ 'geojsonseq[GeoJSON Text Sequence format]' } _export_id_type() { _values 'export unique id type' \ 'counter' \ 'type_id' } _osmium_extract_strategy() { _values 'extract strategy' \ 'simple' \ 'complete_ways' \ 'smart' } _osmium_fileinfo_variables() { _values 'variable' $(osmium fileinfo --show-variables) } _osmium_index_types() { _values 'index types' $(osmium add-locations-to-ways --show-index-types) } _osmium_export_index_types() { _values 'index types' $(osmium export --show-index-types) } _osmium-help() { local -a osmium_help_topics osmium_help_topics=(add-locations-to-ways apply-changes cat diff changeset-filter check-refs derive-changes export extract fileinfo getid help merge merge-changes renumber show sort tags-filter time-filter file-formats index-types) _describe -t osmium-help-topics 'osmium help topics' osmium_help_topics } _osmium "$@"