pax_global_header00006660000000000000000000000064142002341370014506gustar00rootroot0000000000000052 comment=bec0d8c6a058140179fae009858790adc529ec3e osmium-tool-1.14.0/000077500000000000000000000000001420023413700140555ustar00rootroot00000000000000osmium-tool-1.14.0/.clang-tidy000066400000000000000000000062641420023413700161210ustar00rootroot00000000000000--- Checks: '*,-abseil-*,-altera-*,-android-cloexec-*,-bugprone-branch-clone,-bugprone-easily-swappable-parameters,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-macro-usage,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-static-cast-downcast,-cppcoreguidelines-pro-type-vararg,-fuchsia-*,-hicpp-avoid-c-arrays,-hicpp-no-array-decay,-hicpp-vararg,-llvmlibc-*,-misc-no-recursion,-modernize-avoid-c-arrays,-modernize-use-trailing-return-type,-readability-convert-member-functions-to-static,-readability-implicit-bool-conversion,-readability-magic-numbers' # # For a list of check options, see: # https://clang.llvm.org/extra/clang-tidy/checks/list.html # # Disabled checks: # # abseil-* # We are not using abseil. # # altera-* # Doesn't apply. # # android-cloexec-* # O_CLOEXEC isn't available on Windows making this non-portable. # # bugprone-branch-clone # There are several cases in this code where the code seems much more # readable with branch clones than without. # # bugprone-easily-swappable-parameters # Not much we can do about those except inventing new types for everything # and anything. # # cppcoreguidelines-avoid-c-arrays # hicpp-avoid-c-arrays # modernize-avoid-c-arrays # Makes sense for some array, but especially for char arrays using # std::array isn't a good solution. # # cppcoreguidelines-avoid-magic-numbers # readability-magic-numbers # Generally good advice, but there are too many places where this is # useful, for instance in tests. # # cppcoreguidelines-macro-usage # There are cases where we actually need macros. # # cppcoreguidelines-owning-memory # Don't want to add dependency on gsl library. # # cppcoreguidelines-pro-bounds-array-to-pointer-decay # hicpp-no-array-decay # Limited use and many false positives including for all asserts. # # cppcoreguidelines-pro-bounds-pointer-arithmetic # Difficult to get by without it... # # cppcoreguidelines-pro-type-static-cast-downcast # This is needed and totally okay if we are sure about the types. # # cppcoreguidelines-pro-type-vararg # We need some of these functions at least and for some functions it isn't # even clear that those are vararg functions. # # fuchsia-* # Much too strict. # # hicpp-vararg # Too strict, sometimes calling vararg functions is necessary. # # llvmlibc-* # Not applicable. # # misc-no-recursion # Nothing wrong about recursion. # # modernize-use-trailing-return-type # I am not quite that modern. # # readability-convert-member-functions-to-static # Not a bad idea, but it is overzealous when there are member functions # overwritten in child classes and some of them can't be static. # # readability-implicit-bool-conversion # I don't think this makes the code more readable. # #WarningsAsErrors: '*' CheckOptions: - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic value: true - key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic value: true ... osmium-tool-1.14.0/.gitattributes000066400000000000000000000002561420023413700167530ustar00rootroot00000000000000*.osm -crlf *.osc -crlf *.opl -crlf *.osh -crlf *-result.txt -crlf test/export/*.geojson -crlf test/export/*.geojsonseq -crlf test/export/*.txt -crlf test/diff/output* -crlf osmium-tool-1.14.0/.github/000077500000000000000000000000001420023413700154155ustar00rootroot00000000000000osmium-tool-1.14.0/.github/FUNDING.yml000066400000000000000000000000541420023413700172310ustar00rootroot00000000000000custom: "https://osmcode.org/sponsors.html" osmium-tool-1.14.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001420023413700176005ustar00rootroot00000000000000osmium-tool-1.14.0/.github/ISSUE_TEMPLATE/bug-report.md000066400000000000000000000022351420023413700222120ustar00rootroot00000000000000--- name: Report problems with the software about: You found a (possible) bug in osmium-tool title: '' labels: '' assignees: '' --- ## What version of osmium-tool are you using? ## What operating system version are you using? ## Tell us something about your system ## What did you do exactly? ## What did you expect to happen? ## What did happen instead? ## What did you do to try analyzing the problem? osmium-tool-1.14.0/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000002141420023413700215650ustar00rootroot00000000000000contact_links: - name: help.osm.org url: https://help.openstreetmap.org/ about: Ask questions and get support from the community. osmium-tool-1.14.0/.github/actions/000077500000000000000000000000001420023413700170555ustar00rootroot00000000000000osmium-tool-1.14.0/.github/actions/build-windows/000077500000000000000000000000001420023413700216445ustar00rootroot00000000000000osmium-tool-1.14.0/.github/actions/build-windows/action.yml000066400000000000000000000003001420023413700236350ustar00rootroot00000000000000name: Build on Windows runs: using: composite steps: - name: Build run: cmake --build . --config Release --verbose shell: bash working-directory: build osmium-tool-1.14.0/.github/actions/build/000077500000000000000000000000001420023413700201545ustar00rootroot00000000000000osmium-tool-1.14.0/.github/actions/build/action.yml000066400000000000000000000002311420023413700221500ustar00rootroot00000000000000name: Build runs: using: composite steps: - name: Build run: make VERBOSE=1 shell: bash working-directory: build osmium-tool-1.14.0/.github/actions/cmake-windows/000077500000000000000000000000001420023413700216255ustar00rootroot00000000000000osmium-tool-1.14.0/.github/actions/cmake-windows/action.yml000066400000000000000000000006311420023413700236250ustar00rootroot00000000000000name: CMake on Windows runs: using: composite steps: - name: Create build directory run: mkdir build shell: bash - name: Configure run: | cmake -LA .. -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DOsmium_DEBUG=TRUE -DPROTOZERO_INCLUDE_DIR=${GITHUB_WORKSPACE}/../protozero/include shell: bash working-directory: build osmium-tool-1.14.0/.github/actions/cmake/000077500000000000000000000000001420023413700201355ustar00rootroot00000000000000osmium-tool-1.14.0/.github/actions/cmake/action.yml000066400000000000000000000004151420023413700221350ustar00rootroot00000000000000name: CMake runs: using: composite steps: - name: Create build directory run: mkdir build shell: bash - name: Configure run: cmake -LA .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} shell: bash working-directory: build osmium-tool-1.14.0/.github/actions/ctest-windows/000077500000000000000000000000001420023413700216675ustar00rootroot00000000000000osmium-tool-1.14.0/.github/actions/ctest-windows/action.yml000066400000000000000000000002701420023413700236660ustar00rootroot00000000000000name: Test on Windows runs: using: composite steps: - name: Test run: ctest --output-on-failure -C Release shell: bash working-directory: build osmium-tool-1.14.0/.github/actions/ctest/000077500000000000000000000000001420023413700201775ustar00rootroot00000000000000osmium-tool-1.14.0/.github/actions/ctest/action.yml000066400000000000000000000002431420023413700221760ustar00rootroot00000000000000name: ctest runs: using: composite steps: - name: Test run: ctest --output-on-failure shell: bash working-directory: build osmium-tool-1.14.0/.github/actions/install-from-git/000077500000000000000000000000001420023413700222455ustar00rootroot00000000000000osmium-tool-1.14.0/.github/actions/install-from-git/action.yml000066400000000000000000000004711420023413700242470ustar00rootroot00000000000000name: Install Prerequisites from git runs: using: composite steps: - name: Install from git run: | git clone --quiet --depth 1 https://github.com/osmcode/libosmium.git ../libosmium git clone --quiet --depth 1 https://github.com/mapbox/protozero.git ../protozero shell: bash osmium-tool-1.14.0/.github/actions/install-ubuntu/000077500000000000000000000000001420023413700220435ustar00rootroot00000000000000osmium-tool-1.14.0/.github/actions/install-ubuntu/action.yml000066400000000000000000000006641420023413700240510ustar00rootroot00000000000000name: Install Prerequisites on Ubuntu runs: using: composite steps: - name: Install packages run: | sudo apt-get update -q sudo apt-get install -yq \ libboost-dev \ libboost-program-options-dev \ liblz4-dev \ pandoc if [ "$CC" = clang-13 ]; then sudo apt-get install -yq --no-install-suggests --no-install-recommends clang-13; fi shell: bash osmium-tool-1.14.0/.github/workflows/000077500000000000000000000000001420023413700174525ustar00rootroot00000000000000osmium-tool-1.14.0/.github/workflows/ci.yml000066400000000000000000000132451420023413700205750ustar00rootroot00000000000000name: CI on: [ push, pull_request ] jobs: linux: runs-on: ubuntu-latest timeout-minutes: 30 strategy: fail-fast: false matrix: image: - "ubuntu:18.04" # gcc 7.5.0, clang 6.0.0, cmake 3.10.2 - "ubuntu:20.04" # gcc 9.3.0, clang 10.0.0, cmake 3.16.3 - "ubuntu:21.04" # gcc 10.3.0, clang 12.0.0, cmake 3.18.4 - "debian:stretch" # gcc 6.3.0, clang 3.8.1, cmake 3.7.2 - "debian:buster" # gcc 8.3.0, clang 7.0.1, cmake 3.13.4 - "debian:bullseye" # gcc 10.2.1, clang 11.0.1, cmake 3.18.4 - "debian:testing" # gcc 10.3.0, clang 11.1.0, cmake 3.21.3 - "debian:experimental" # gcc 11.0.0, clang 14.0.0, cmake 3.21.3 - "fedora:34" # gcc 11.2.1, clang 12.0.1, cmake 3.20.5 - "fedora:35" # gcc 11.2.1, clang 13.0.0, cmake 3.22.0 build_type: [Dev] cpp_compiler: [g++] cpp_version: [c++14] include: - image: "debian:bullseye" cpp_version: c++17 - image: "debian:bullseye" cpp_version: c++20 - image: "debian:bullseye" c_compiler: clang cpp_compiler: clang++ cpp_version: c++17 - image: "debian:bullseye" c_compiler: clang cpp_compiler: clang++ cpp_version: c++20 - image: "debian:bullseye" build_type: RelWithDebInfo - image: "debian:bullseye" c_compiler: clang cpp_compiler: clang++ - image: "debian:testing" CXXFLAGS: -Wno-stringop-overread - image: "debian:testing" c_compiler: clang cpp_compiler: clang++ - image: "debian:experimental" CXXFLAGS: -Wno-stringop-overread - image: "debian:experimental" c_compiler: clang-14 cpp_compiler: clang++-14 - image: "fedora:34" CXXFLAGS: -Wno-stringop-overread - image: "fedora:35" CXXFLAGS: -Wno-stringop-overread container: image: ${{ matrix.image }} env: BUILD_TYPE: ${{ matrix.build_type }} CC: ${{ matrix.c_compiler }} CXX: ${{ matrix.cpp_compiler }} CXXFLAGS: ${{ matrix.CXXFLAGS }} LDFLAGS: ${{ matrix.LDFLAGS }} CPP_VERSION: ${{ matrix.cpp_version }} APT_LISTCHANGES_FRONTEND: none DEBIAN_FRONTEND: noninteractive steps: - name: Prepare container (apt) shell: bash if: startsWith(matrix.image, 'debian:') || startsWith(matrix.image, 'ubuntu:') run: | apt-get update -qq apt-get install -y \ clang \ cmake \ g++ \ git \ libboost-dev \ libboost-program-options-dev \ libbz2-dev \ libexpat1-dev \ liblz4-dev \ make \ pandoc \ zlib1g-dev - name: Install compiler shell: bash if: matrix.cpp_compiler == 'clang++-14' run: apt-get install -y --no-install-suggests --no-install-recommends clang-14 - name: Prepare container (dnf) shell: bash if: startsWith(matrix.image, 'fedora:') run: | dnf install --quiet --assumeyes \ boost-devel \ bzip2-devel \ cmake \ expat-devel \ gcc-c++ \ git \ lz4-devel \ make \ pandoc \ zlib-devel - uses: actions/checkout@v2 - uses: ./.github/actions/install-from-git - uses: ./.github/actions/cmake - uses: ./.github/actions/build - uses: ./.github/actions/ctest ubuntu-latest: runs-on: ubuntu-20.04 env: CC: clang-13 CXX: clang++-13 BUILD_TYPE: Dev steps: - name: Install new clang run: | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-13 main' shell: bash - uses: actions/checkout@v2 - uses: ./.github/actions/install-ubuntu - uses: ./.github/actions/install-from-git - uses: ./.github/actions/cmake - uses: ./.github/actions/build - uses: ./.github/actions/ctest macos: timeout-minutes: 30 strategy: fail-fast: false matrix: os: - "macos-10.15" - "macos-11.0" build_type: [Dev] include: - os: "macos-11.0" build_type: Release runs-on: ${{ matrix.os }} env: CC: clang CXX: clang++ BUILD_TYPE: ${{ matrix.build_type }} steps: - run: brew install boost - uses: actions/checkout@v2 - uses: ./.github/actions/install-from-git - uses: ./.github/actions/cmake - uses: ./.github/actions/build - uses: ./.github/actions/ctest windows: timeout-minutes: 30 strategy: fail-fast: false matrix: os: - windows-2019 - windows-2022 runs-on: ${{ matrix.os }} steps: - run: | vcpkg install \ boost-iterator:x64-windows \ boost-program-options:x64-windows \ boost-variant:x64-windows \ bzip2:x64-windows \ expat:x64-windows \ lz4:x64-windows \ zlib:x64-windows shell: bash - uses: actions/checkout@v2 with: submodules: true - uses: ./.github/actions/install-from-git - uses: ./.github/actions/cmake-windows - uses: ./.github/actions/build-windows - uses: ./.github/actions/ctest-windows osmium-tool-1.14.0/.gitignore000066400000000000000000000000621420023413700160430ustar00rootroot00000000000000.*.swp .ycm_extra_conf.pyc /build /libosmium-deps osmium-tool-1.14.0/.ycm_extra_conf.py000066400000000000000000000023041420023413700175040ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # Configuration for YouCompleteMe Vim plugin # # https://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++14', # '-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.14.0/CHANGELOG.md000066400000000000000000000646071420023413700157030ustar00rootroot00000000000000 # Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). ## [unreleased] - ### Added ### Changed ### Fixed ## [1.14.0] - 2022-02-07 ### Added - Add `--keep-member-nodes` option to `add-locations-to-ways` command. When this is set, all nodes referenced directly from relations are kept in the output. If this is used, the input file is read twice an a bit more memory is needed. Osmium will run around 15% longer than without this option. - Add `-S relations=false` option to `complete_ways` extract strategy. If you don't need any relations you can set this when using `osmium extract` and the extract will be done more quickly. - New `--clean` option to `osmium extract` command to clean attributes. ### Changed - Switch to C++14 and CMake 3.5.0 as a minimum requirements. - Switch to [Catch version 2](https://github.com/catchorg/Catch2/tree/v2.x) testing framework. ### Fixed - Fix possible crash when pager set for `osmium show` command was less then 4 characters long. - Fixed hangup in `osmium show` when a non-existing pager was used. - Fixed some tests. - Fix/improve error detection in export code. More errors are detected now which makes a difference when the `-e` or `-E` options are used. ## [1.13.2] - 2021-10-05 ### Added - New `osmium removeid` command to remove all objects with the specified IDs from an OSM file. (This is, in a way, the opposite of the `osmium getid` command.) - New `osmium-output-headers(5)` man page with details about the settings supported by the `--output-header` command line option. - New `-g header.boxes` output option to `osmium fileinfo` to get the bounding box(es) set in the header. - New option `--attributes` for the export command to specified attributes that should show up in the output files. (This needed a config file before.) - New option `--buffer-data` for `osmium cat` command to buffer all read data in memory before writing it out again. Can be used for benchmarking. ### Changed - The `osmium merge` command now checks that the input files are ordered correctly and warns or stops if this is not the case. - Improved messages about files read in verbose mode for `osmium cat`. ### Fixed - Fixed relation member recursion in tags-filter so that objects referenced from matching relations are also in the output. - Fix point-in-polygon-check in extract command. More nodes directly on the boundary should now be inside the polygon. This fixes a problem with extracts on the antimeridian. - When an output file name for the extract command contains multiple dots (.), the file type could not always be deduced correctly. This improves detection for .json and .poly files. - Do not show progress when any of the inputs is stdin. Because we don't know how large the input file is we can't display a reliable progress indicator. - Allow `none` index type on `osmium export`. ## [1.13.1] - 2021-02-01 ### Changed - Update `osmium-file-formats` man page to include newer file format options. ### Fixed - The `extract` command did not work correctly on history files. Sometimes deleted objects were not detected as such and the resulting file was not a correct history file. - Open input file only once in `tags-filter` command if `-R`, `--omit-referenced` is used. This way it works when reading from STDIN. ## [1.13.0] - 2021-01-08 ### Added - Add support for negative IDs in add-locations-to-ways command. - Show setting of `-i`, `--invert-match` option on tags-filter command. - Show bytes read and written in verbose mode in `osmium cat` output. ### Changed - Now depends on libosmium 2.16.0 or greater. - Has support for PBF lz4 compression which is enabled by default if the library is found. Disable by setting CMake option `WITH_LZ4` to `OFF`. - An OSM file header can now be set based on the input file header in extract command from the config file. Set the header to the special `null` value for this. - The `fileinfo` command now shows a **Metadata** section as described in the man page. ### Fixed - When using the `-I`, `--id-osm-file` option in the `tags-filter` command, not only the objects in the specified file were marked but also the nodes referenced from ways and the members referenced from relations. This had two results: a) When not using `-r`, `--add-referenced`: too many objects ended up in the resulting file. b) When using `-t`, `--remove-tags`: tags from those member objects were not removed. - When change files have been created from extracts it is possible that they contain objects with the same type, id, version, and timestamp. In that case we still want to get the last object available. This is now done correctly. - Various man page fixes. ## [1.12.1] - 2020-06-27 ### Changed * Require libosmium 2.15.6 which has an important fix related to multipolygons assembly (needed for "osmium export"). ## [1.12.0] - 2020-04-21 ### Added * New `osmium tags-count` command. * New `--clean` option to `osmium cat` command to clean attributes. ### Fixed * Allow index types with file name in export command. ## [1.11.1] - 2019-11-20 ### Added * Introduce a generic facility for setting output format options. They can be set on the command line (`--format-option`/`-x`) or in the `format_options` section in the config file. Settings can be any OPTION=VALUE type string. There are two new settings: For the geojsonseq format, the option `print_record_separator=false` replaces the command line option `--omit-rs`/`-r` which is now deprecated. The `tags_format` option for the Pg output format allows using the `hstore` type for tags instead of `json(b)`. ### Changed * Open output file earlier in tags-filter command, so we see it immediately in case this fails. ### Fixed * When tags-filter is used with `--remove-tags`, matching ways got their tags removed if they are also referenced from relations. This was clearly wrong. ## [1.11.0] - 2019-09-16 ### Added * New option `--remove-tags`/`-t` to `getid` command. When used the tags of all objects are removed that are not explicitly requested but are only included to complete references. * Add `create-locations-index` and `query-locations-index` commands. These are used to create, update, query and dump node location indexes on disk. These indexes store the location of nodes, typically to add them to ways and relations later. It is the same format used by osm2pgsql (they call it "flat node store") and by the `add-locations-to-ways` command. * Support for new [Spaten](https://thomas.skowron.eu/spaten/) export format. * Add special syntax for `--output-header` to copy header from input. Sometimes it is useful to copy header fields from the input to the output, for instance the `osmosis_replication_timestamp` field. This can now be done for some commands (currently only `extract`) by using the special syntax `--output-header=OPTION!`, i.e. using an exclamation mark instead of setting a value. ### Changed * Better checking of coordinates in extract boundary polygons/bboxes. * Compile with NDEBUG in RelWithDebInfo mode. * Various code cleanups based on problems found with clang-tidy. * Updated Catch to version 1.12.2. * Mark PBF output of extract, renumber, and sort commands as sorted. Uses the new header option `sorting` of the libosmium library which is not in a released version yet. This sets the `Sort.Type_then_ID` header property in the PBF file. ### Fixed * Only check if way is closed after check that it contains nodes. * `get_start_id()` is not `noexcept`. * Man pages correctly show options starting with double dash and other small man page fixes. * Allow file-based location index types (`dense_file_array` and `sparse_file_array`) that need a file name. Using them was not possible because of an overzealous check that didn't recognize the file name. ## [1.10.0] - 2018-12-10 ### Added * The `fileinfo` command now has an `--object-type`/`-t` option like some other commands. * Extended `fileinfo` command to show internal buffer counts and sizes. * Add `--strategy` option to `sort` command. New `multipass` strategy which reads the input file(s) three times making the sort a bit slower, but also using less memory. * New option `--remove-tags`/`-t` to `tags-filter` command. When used the tags of all objects that are not matching the filter expression but are included as references are removed. * New option for smart extract strategy: `complete-partial-relations=X` will complete all relations with at least X percent of their members already in the extract. * New export format "pg" creates a file in the PostgreSQL COPY text format with the GEOMETRY as WKB and the tags in JSON(B) format. This can be imported into a PostgreSQL/PostGIS database very quickly. ### Changed * Show better error message if output directory is missing for `extract` command. ### Fixed * Several fixes for the `tags-filter` command which could lead to wrong results. ## [1.9.1] - 2018-08-18 ### Changed * Improved `export` command man page. ### Fixed * Regression: Default for `linear_tags` and `area_tags` should be `true`. It was before v1.9.0 and it is documented this way. ## [1.9.0] - 2018-08-11 ### Added - Add area matching to `tags-filter`. The `tags-filter` command can now match "areas" using the "a/" prefix. Areas in this sense are all closed ways with 4 or more nodes and all relations with tag "type=multipolygon" or "type=boundary". - Add `--geometry-types` option to the `export` command allowing you to restrict the geometry types written out. - Also print out smallest node, way, and relation ID in `fileinfo` command. - In the `renumber` command, the start IDs for nodes, ways, and relations can now be set together or separately with the `--start-id` option. Negative IDs are now also allowed. Also there is a new `--show-index` function that prints out the ID mappings in the index. - More tests and updated documentation. - Add `-C`, `--print-default-config` option to the `export` command writing out the default configuration to stdout. - New `getparents` command to get the ways used by specified nodes or relations having specified members. ### Changed - Newest version of libosmium (2.14.2) and protozoro (1.6.3) are now required. - Calculation of CRC32 in the fileinfo command is now optional. Calculating the CRC32 is very expensive and going without it makes the program much much faster. Use --crc/-c to enable it. It will also be automatically enabled for JSON output to stay compatible with earlier versions of Osmium which might be used in an automated context (you can disable this with `--no-crc`). It is also enabled if `-g data.crc32` is specified. If it is enabled we are using the CRC32 implementation from zlib which is faster than the one from boost we used before. This is possible through some changes in libosmium. - Treat ways with same node end locations as closed in `export` command instead of looking at the IDs. This is more consistent with what the libosmium `MultipolygonManager` does. - In the `export` command, the decision whether a way is treated as a linestring or polygon has changed. See the man page for details. - Create linestring geometries for untagged ways if `-n` or `--keep-untagged` option is set. It doesn't matter whether they are closed or not, they are only written out as linestrings. ### Fixed - Show error for ways with less than 2 nodes if --show-errors is set. - Attributes (such as id, version, timestamp, etc.) can appear in the properties of the output with arbitrary configurable names. These could overlap with tag keys which we don't want. This change removes tags with those keys on the assumption that the names chosen for the attributes are sufficiently different (something like "@id") from normal tag keys that this will not happen very often and those tags are useless anyway. - Make `--(no)-progress` option work in `sort` command. ## [1.8.0] - 2018-03-31 ### Added - Support for negative IDs in export command. - Lots of tests with missing metadata (Thanks to Michael Reichert). - Add metadata options to the extended output of fileinfo command (Thanks to Michael Reichert). - Add progress bars to many commands. - Add `--redact` option to the `apply-changes` command to redact (patch) history files. The change files can contain any version of any object which will replace that version of that object from the input. This allows changing the history! This mode is for special use only, for instance to remove copyrighted or private data. ### Changed - Needs libosmium 2.14.0. - Update included `catch.hpp` to version 1.12.1. - Removed Makefile. Undocumented and possibly confusing way of building. As documented, use CMake directly instead. - Allow bbox setting with any two opposing corners, instead of insisting on bottom-left and top-right corner. This affects the changeset-filter and extract commands. - Allow GeoJSON input file to have a FeatureCollection instead of a Feature. Only the first feature of this collection is used. ### Fixed - Bug in the derive-changes command if it is used without `--keep-details`. A deletion of any type of object was written as a deletion of a node. (Thanks to Michael Reichert.) - Fix assertion failure in diff command. - Throw exception instead of using assert to catch broken rings. - Disable progress bar if STDOUT isn't a tty. - Show error when there are no extracts specified in extract command. - Improve STDIN handling in extract command. STDIN can now be used with the `simple` strategy, with other strategies it will give you a nice error message. - Lots of code cleanups based on `clang-tidy` warnings making the code more robust. - Only install manpage directories, not CMake files. (Thanks Bas Couwenberg.) ## [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.14.0...HEAD [1.14.0]: https://github.com/osmcode/osmium-tool/compare/v1.13.2...v1.14.0 [1.13.2]: https://github.com/osmcode/osmium-tool/compare/v1.13.1...v1.13.2 [1.13.1]: https://github.com/osmcode/osmium-tool/compare/v1.13.0...v1.13.1 [1.13.0]: https://github.com/osmcode/osmium-tool/compare/v1.12.1...v1.13.0 [1.12.1]: https://github.com/osmcode/osmium-tool/compare/v1.12.0...v1.12.1 [1.12.0]: https://github.com/osmcode/osmium-tool/compare/v1.11.1...v1.12.0 [1.11.1]: https://github.com/osmcode/osmium-tool/compare/v1.11.0...v1.11.1 [1.11.0]: https://github.com/osmcode/osmium-tool/compare/v1.10.0...v1.11.0 [1.10.0]: https://github.com/osmcode/osmium-tool/compare/v1.9.1...v1.10.0 [1.9.1]: https://github.com/osmcode/osmium-tool/compare/v1.9.0...v1.9.1 [1.9.0]: https://github.com/osmcode/osmium-tool/compare/v1.8.0...v1.9.0 [1.8.0]: https://github.com/osmcode/osmium-tool/compare/v1.7.1...v1.8.0 [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.14.0/CMakeLists.txt000066400000000000000000000225621420023413700166240ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool # #----------------------------------------------------------------------------- cmake_minimum_required(VERSION 3.5.0) project(osmium VERSION 1.14.0 LANGUAGES CXX C) 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) set(AUTHOR "Jochen Topf ") set(CMAKE_EXPORT_COMPILE_COMMANDS ON) option(WITH_LZ4 "Build with lz4 support for PBF files" ON) option(BUILD_TESTING "Build the tests" ON) #----------------------------------------------------------------------------- # # Find external dependencies # #----------------------------------------------------------------------------- find_package(Boost 1.55.0 REQUIRED COMPONENTS program_options) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) find_package(Osmium 2.16.0 REQUIRED COMPONENTS io) include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS}) if(WITH_LZ4) find_package(LZ4) if(LZ4_FOUND) message(STATUS "lz4 library found, compiling with it") add_definitions(-DOSMIUM_WITH_LZ4) include_directories(SYSTEM ${LZ4_INCLUDE_DIRS}) list(APPEND OSMIUM_LIBRARIES ${LZ4_LIBRARIES}) else() message(WARNING "lz4 library not found, compiling without it") endif() else() message(STATUS "Building without lz4 support: Set WITH_LZ4=ON to change this") endif() #----------------------------------------------------------------------------- # # 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++14 ${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 # https://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++14). # #----------------------------------------------------------------------------- if(NOT MSVC) if(NOT USE_CPP_VERSION) set(USE_CPP_VERSION c++14) endif() message(STATUS "Use C++ version: ${USE_CPP_VERSION}") add_compile_options(-std=${USE_CPP_VERSION}) endif() #----------------------------------------------------------------------------- # # Compiler and Linker flags # #----------------------------------------------------------------------------- if(MSVC) set(DEV_COMPILE_OPTIONS "/Ox") set(RWD_COMPILE_OPTIONS "/Ox /DNDEBUG") else() set(DEV_COMPILE_OPTIONS "-O3 -g") set(RWD_COMPILE_OPTIONS "-O3 -g -DNDEBUG") endif() if(WIN32) add_definitions(-DWIN32 -D_WIN32 -DMSWIN32 -DBGDWIN32) endif() set(CMAKE_CXX_FLAGS_DEV "${DEV_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 "${RWD_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) #----------------------------------------------------------------------------- SET(OSMIUM_COMMANDS add-locations-to-ways apply-changes cat changeset-filter check-refs create-locations-index derive-changes diff export extract fileinfo getid getparents merge merge-changes query-locations-index removeid renumber show sort tags-count tags-filter time-filter ) set(OSMIUM_SOURCE_FILES cmd.cpp cmd_factory.cpp id_file.cpp io.cpp util.cpp command_help.cpp option_clean.cpp export/export_format_json.cpp export/export_format_pg.cpp export/export_format_spaten.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/geometry_util.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 ) foreach(_command ${OSMIUM_COMMANDS}) string(REPLACE "-" "_" _ucmd ${_command}) list(APPEND OSMIUM_SOURCE_FILES "command_${_ucmd}.cpp") endforeach() add_subdirectory(man) add_subdirectory(src) #----------------------------------------------------------------------------- # # Tests # #----------------------------------------------------------------------------- if(BUILD_TESTING) enable_testing() add_subdirectory(test) endif() #----------------------------------------------------------------------------- # # Optional "clang-tidy" target # #----------------------------------------------------------------------------- message(STATUS "Looking for clang-tidy") find_program(CLANG_TIDY NAMES clang-tidy clang-tidy-14 clang-tidy-13 clang-tidy-12 clang-tidy-11) if(CLANG_TIDY) message(STATUS "Looking for clang-tidy - found ${CLANG_TIDY}") file(GLOB _unit_tests RELATIVE "${CMAKE_SOURCE_DIR}/src" "${CMAKE_SOURCE_DIR}/test/*/*.cpp") add_custom_target(clang-tidy ${CLANG_TIDY} -p ${CMAKE_BINARY_DIR} ${OSMIUM_SOURCE_FILES} ${_unit_tests} WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/src" ) else() message(STATUS "Looking for clang-tidy - not found") message(STATUS " Build target 'clang-tidy' will not be available.") endif() #----------------------------------------------------------------------------- # # Test install # # Does a local install and checks that the files we expect to be installed # are installed and no extra files are installed. If this fails make sure # the list of files in cmake/test_install.cmake is correct. Only enables # if the WITH_EXTRA_TESTS option is set, because this test fails on some # platforms even if everything is correct. # #----------------------------------------------------------------------------- option(WITH_EXTRA_TESTS "Run extra tests (usually only for developers)") if(WITH_EXTRA_TESTS) add_test(NAME testinstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/cmake/test_install.cmake) endif() #----------------------------------------------------------------------------- osmium-tool-1.14.0/CONTRIBUTING.md000066400000000000000000000012071420023413700163060ustar00rootroot00000000000000 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 were trying to achieve, 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.14.0/LICENSE-rapidjson.txt000066400000000000000000000070421420023413700176720ustar00rootroot00000000000000Tencent 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.14.0/LICENSE.txt000066400000000000000000001045231420023413700157050ustar00rootroot00000000000000 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.14.0/README.md000066400000000000000000000112511420023413700153340ustar00rootroot00000000000000 # Osmium Command Line Tool A multipurpose command line tool for working with OpenStreetMap data based on the Osmium library. Official web site: https://osmcode.org/osmium-tool/ [![Github Build Status](https://github.com/osmcode/osmium-tool/workflows/CI/badge.svg?branch=master)](https://github.com/osmcode/osmium-tool/actions) [![Appveyor Build status](https://ci.appveyor.com/api/projects/status/k9v6et0o4baekrmi/branch/master?svg=true)](https://ci.appveyor.com/project/lonvia/osmium-tool/branch/master) ## Prerequisites You need a C++14 compliant compiler. You also need the following libraries: Libosmium (>= 2.16.0) https://osmcode.org/libosmium Debian/Ubuntu: libosmium2-dev Fedora/CentOS: libosmium-devel Protozero (>= 1.6.3) https://github.com/mapbox/protozero Debian/Ubuntu: libprotozero-dev Fedora/CentOS: protozero-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) https://www.boost.org/doc/libs/1_55_0/doc/html/program_options.html Debian/Ubuntu: libboost-program-options-dev Fedora/CentOS: boost-devel openSUSE: boost-devel (use 'libboost_program_options-devel' for modern OS versions) bz2lib http://www.bzip.org/ Debian/Ubuntu: libbz2-dev Fedora/CentOS: bzip2-devel openSUSE: libbz2-devel zlib https://www.zlib.net/ Debian/Ubuntu: zlib1g-dev Fedora/CentOS: zlib-devel openSUSE: zlib-devel LZ4 (optional) https://lz4.github.io/lz4/ Debian/Ubuntu: liblz4-dev Only needed for LZ4 PBF compression. Expat https://libexpat.github.io/ Debian/Ubuntu: libexpat1-dev Fedora/CentOS: expat-devel openSUSE: libexpat-devel cmake https://cmake.org/ Debian/Ubuntu: cmake Fedora/CentOS: cmake openSUSE: cmake Pandoc (Needed to build documentation, optional) https://pandoc.org/ Debian/Ubuntu: pandoc Fedora/CentOS: pandoc openSUSE: pandoc On Linux systems most of these libraries are available through your package manager, see the list above for the names of the packages. But make sure to check the versions. If the packaged version available is not new enough, you'll have to install from source. Most likely this is the case for Protozero and Libosmium. On macOS many of the libraries above will be available through Homebrew. When building the tool, CMake will automatically look for these libraries in the usual places on your system. In addition it will look for the Libosmium and Protozero libraries in the same directory where this Osmium repository is. So if you are building from the Git repository and want to use the newest Libosmium, Protozero, and Osmium, clone all of them into the same directory: mkdir work cd work git clone https://github.com/mapbox/protozero git clone https://github.com/osmcode/libosmium git clone https://github.com/osmcode/osmium-tool ## Building Osmium uses CMake for its builds. On Linux and macOS you can build as follows: cd osmium-tool mkdir build cd build cmake .. ccmake . ## optional: change CMake settings if needed 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. Please read the CMake documentation and get familiar with the `cmake` and `ccmake` tools which have many more options. On Windows you can compile with the Visual Studio C++ compiler and nmake. The necessary dependencies can be installed with [conda](https://conda.io). See `appveyor.yml` for the necessary commands to compile osmium-tool. ## Documentation See the [Osmium Tool website](https://osmcode.org/osmium-tool/) and [Osmium Tool Manual](https://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-2022 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.14.0/appveyor.yml000066400000000000000000000013441420023413700164470ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # Configuration for continuous integration service at appveyor.com # #----------------------------------------------------------------------------- environment: matrix: - config: Debug - config: Release shallow_clone: true # Operating system (build VM template) os: Visual Studio 2015 platform: x64 # scripts that are called at very beginning, before repo cloning init: # clone directory clone_folder: c:\projects\osmium-tool install: - cd c:\projects - git clone --depth 1 https://github.com/osmcode/libosmium - git clone --depth 1 https://github.com/mapbox/protozero build_script: - cd c:\projects/osmium-tool - build-appveyor.bat osmium-tool-1.14.0/build-appveyor.bat000066400000000000000000000037751420023413700175230ustar00rootroot00000000000000@ECHO OFF SETLOCAL SET EL=0 ECHO ~~~~~~ %~f0 ~~~~~~ SET 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 CD .. nuget install expat.v140 -Version 2.2.5 IF %ERRORLEVEL% NEQ 0 GOTO ERROR SET PATH=C:/projects/expat.v140.2.2.5/build/native/bin/x64/%config%;%PATH% nuget install zlib-vc140-static-64 -Version 1.2.11 IF %ERRORLEVEL% NEQ 0 GOTO ERROR nuget install bzip2.v140 -Version 1.0.6.9 IF %ERRORLEVEL% NEQ 0 GOTO ERROR SET PATH=C:/projects/bzip2.v140.1.0.6.9/build/native/bin/x64/%config%;%PATH% CD osmium-tool ECHO config^: %config% SET libpostfix="" IF "%config%"=="Debug" SET libpostfix="d" 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 SET CMAKE_CMD=cmake .. -LA -G "Visual Studio 14 Win64" ^ -DOsmium_DEBUG=TRUE ^ -DCMAKE_BUILD_TYPE=%config% ^ -DBOOST_ROOT=C:/Libraries/boost_1_63_0 ^ -DZLIB_INCLUDE_DIR=C:/projects/zlib-vc140-static-64.1.2.11/lib/native/include ^ -DZLIB_LIBRARY=C:/projects/zlib-vc140-static-64.1.2.11/lib/native/libs/x64/static/%config%/zlibstatic.lib ^ -DEXPAT_INCLUDE_DIR=C:/projects/expat.v140.2.2.5/build/native/include ^ -DEXPAT_LIBRARY=C:/projects/expat.v140.2.2.5/build/native/lib/x64/%config%/libexpat%libpostfix%.lib ^ -DBZIP2_INCLUDE_DIR=C:/projects/bzip2.v140.1.0.6.9/build/native/include ^ -DBZIP2_LIBRARIES=C:/projects/bzip2.v140.1.0.6.9/build/native/lib/x64/%config%/libbz2%libpostfix%.lib ^ -DBoost_USE_STATIC_LIBS=ON 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.14.0/build-local.bat000066400000000000000000000010571420023413700167370ustar00rootroot00000000000000@ECHO OFF SETLOCAL SET EL=0 ECHO ~~~~~~ %~f0 ~~~~~~ ECHO. ECHO build-local ["config=Dev"] ECHO default config^: Release ECHO. SET platform=x64 SET config=Release :: OVERRIDE PARAMETERS >>>>>>>> :NEXT-ARG IF '%1'=='' GOTO ARGS-DONE ECHO setting %1 SET %1 SHIFT GOTO NEXT-ARG :ARGS-DONE ::<<<<< OVERRIDE PARAMETERS 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.14.0/cmake/000077500000000000000000000000001420023413700151355ustar00rootroot00000000000000osmium-tool-1.14.0/cmake/FindLZ4.cmake000066400000000000000000000025321420023413700173530ustar00rootroot00000000000000find_path(LZ4_INCLUDE_DIR NAMES lz4.h DOC "lz4 include directory") mark_as_advanced(LZ4_INCLUDE_DIR) find_library(LZ4_LIBRARY NAMES lz4 liblz4 DOC "lz4 library") mark_as_advanced(LZ4_LIBRARY) if (LZ4_INCLUDE_DIR) file(STRINGS "${LZ4_INCLUDE_DIR}/lz4.h" _lz4_version_lines REGEX "#define[ \t]+LZ4_VERSION_(MAJOR|MINOR|RELEASE)") string(REGEX REPLACE ".*LZ4_VERSION_MAJOR *\([0-9]*\).*" "\\1" _lz4_version_major "${_lz4_version_lines}") string(REGEX REPLACE ".*LZ4_VERSION_MINOR *\([0-9]*\).*" "\\1" _lz4_version_minor "${_lz4_version_lines}") string(REGEX REPLACE ".*LZ4_VERSION_RELEASE *\([0-9]*\).*" "\\1" _lz4_version_release "${_lz4_version_lines}") set(LZ4_VERSION "${_lz4_version_major}.${_lz4_version_minor}.${_lz4_version_release}") unset(_lz4_version_major) unset(_lz4_version_minor) unset(_lz4_version_release) unset(_lz4_version_lines) endif () include(FindPackageHandleStandardArgs) find_package_handle_standard_args(LZ4 REQUIRED_VARS LZ4_LIBRARY LZ4_INCLUDE_DIR VERSION_VAR LZ4_VERSION) if (LZ4_FOUND) set(LZ4_INCLUDE_DIRS "${LZ4_INCLUDE_DIR}") set(LZ4_LIBRARIES "${LZ4_LIBRARY}") if (NOT TARGET LZ4::LZ4) add_library(LZ4::LZ4 UNKNOWN IMPORTED) set_target_properties(LZ4::LZ4 PROPERTIES IMPORTED_LOCATION "${LZ4_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${LZ4_INCLUDE_DIR}") endif () endif () osmium-tool-1.14.0/cmake/FindOsmium.cmake000066400000000000000000000325061420023413700202170ustar00rootroot00000000000000#---------------------------------------------------------------------- # # 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 (deprecated!) # lz4 - include support for LZ4 compression of PBF files # # 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 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) if(NOT EXISTS "${OSMIUM_INCLUDE_DIR}/osmium/version.hpp") message(FATAL_ERROR "Missing ${OSMIUM_INCLUDE_DIR}/osmium/version.hpp. Either your libosmium version is too old, or libosmium wasn't found in the place you said.") endif() 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) find_package(Protozero 1.6.3) if(Osmium_USE_LZ4) find_package(LZ4 REQUIRED) add_definitions(-DOSMIUM_WITH_LZ4) endif() list(APPEND OSMIUM_EXTRA_FIND_VARS ZLIB_FOUND Threads_FOUND PROTOZERO_INCLUDE_DIR) if(ZLIB_FOUND AND Threads_FOUND AND PROTOZERO_FOUND) list(APPEND OSMIUM_PBF_LIBRARIES ${ZLIB_LIBRARIES} ${LZ4_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) list(APPEND OSMIUM_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR} ${LZ4_INCLUDE_DIRS} ${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) message(WARNING "Osmium: Use of Google SparseHash is deprecated. Please switch to a different index type.") 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 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # 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.14.0/cmake/FindProtozero.cmake000066400000000000000000000037601420023413700207510ustar00rootroot00000000000000#---------------------------------------------------------------------- # # FindProtozero.cmake # # Find the protozero headers. # #---------------------------------------------------------------------- # # 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(Protozero [version] [REQUIRED]) # include_directories(SYSTEM ${PROTOZERO_INCLUDE_DIR}) # # The version number is optional. If it is not set, any version of # protozero will do. # # if(NOT PROTOZERO_FOUND) # message(WARNING "Protozero not found!\n") # endif() # #---------------------------------------------------------------------- # # Variables: # # PROTOZERO_FOUND - True if Protozero was found. # PROTOZERO_INCLUDE_DIR - Where to find include files. # #---------------------------------------------------------------------- # find include path find_path(PROTOZERO_INCLUDE_DIR protozero/version.hpp PATH_SUFFIXES include PATHS ${CMAKE_SOURCE_DIR}/../protozero ) # Check version number if(Protozero_FIND_VERSION) file(STRINGS "${PROTOZERO_INCLUDE_DIR}/protozero/version.hpp" _version_define REGEX "#define PROTOZERO_VERSION_STRING") if("${_version_define}" MATCHES "#define PROTOZERO_VERSION_STRING \"([0-9.]+)\"") set(_version "${CMAKE_MATCH_1}") else() set(_version "unknown") endif() endif() #set(PROTOZERO_INCLUDE_DIRS "${PROTOZERO_INCLUDE_DIR}") include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Protozero REQUIRED_VARS PROTOZERO_INCLUDE_DIR VERSION_VAR _version) #---------------------------------------------------------------------- osmium-tool-1.14.0/cmake/run_test_compare_output.cmake000066400000000000000000000042211420023413700231270ustar00rootroot00000000000000# # 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 the same as variable 'return_code'. # 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 ("$ENV{osmium_cmake_stderr}" STREQUAL "ignore")) if(NOT (stderr STREQUAL "")) message(SEND_ERROR "Command tested wrote to stderr: ${stderr}") endif() endif() if(NOT result EQUAL ${return_code}) message(FATAL_ERROR "Error when calling '${cmd}': ${result} (should be ${return_code})") 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.14.0/cmake/run_test_compare_output_return.cmake000066400000000000000000000041601420023413700245300ustar00rootroot00000000000000# # 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 ("$ENV{osmium_cmake_stderr}" STREQUAL "ignore")) if(NOT (stderr STREQUAL "")) message(SEND_ERROR "Command tested wrote to stderr: ${stderr}") endif() endif() if(NOT result EQUAL ${return_code}) message(FATAL_ERROR "Error when calling '${cmd}': ${result} (should be ${return_code})") 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.14.0/cmake/test_install.cmake000066400000000000000000000037331420023413700206520ustar00rootroot00000000000000 set(OSMIUM_INSTALL_FILES share/man/man1/osmium-add-locations-to-ways.1 share/man/man1/osmium-apply-changes.1 share/man/man1/osmium-cat.1 share/man/man1/osmium-changeset-filter.1 share/man/man1/osmium-check-refs.1 share/man/man1/osmium-create-locations-index.1 share/man/man1/osmium-derive-changes.1 share/man/man1/osmium-diff.1 share/man/man1/osmium-export.1 share/man/man1/osmium-extract.1 share/man/man1/osmium-fileinfo.1 share/man/man1/osmium-getid.1 share/man/man1/osmium-getparents.1 share/man/man1/osmium-merge-changes.1 share/man/man1/osmium-merge.1 share/man/man1/osmium-query-locations-index.1 share/man/man1/osmium-removeid.1 share/man/man1/osmium-renumber.1 share/man/man1/osmium-show.1 share/man/man1/osmium-sort.1 share/man/man1/osmium-tags-count.1 share/man/man1/osmium-tags-filter.1 share/man/man1/osmium-time-filter.1 share/man/man1/osmium.1 share/man/man5/osmium-file-formats.5 share/man/man5/osmium-index-types.5 share/man/man5/osmium-output-headers.5 bin/osmium ) execute_process(COMMAND ${CMAKE_COMMAND} -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/test_install -P ${CMAKE_BINARY_DIR}/cmake_install.cmake) file(READ ${CMAKE_BINARY_DIR}/install_manifest.txt _manifest) string(REPLACE "\n" ";" _files "${_manifest}") string(REPLACE "${CMAKE_BINARY_DIR}/test_install/" "" _file_list "${_files}") list(SORT OSMIUM_INSTALL_FILES) list(SORT _file_list) if(NOT "${OSMIUM_INSTALL_FILES}" STREQUAL "${_file_list}") foreach(_file IN LISTS OSMIUM_INSTALL_FILES) list(FIND _file_list ${_file} _result) if(${_result} EQUAL -1) message(STATUS "Missing file in install: ${_file}") else() list(REMOVE_ITEM _file_list ${_file}) endif() endforeach() if(NOT "${_file_list}" STREQUAL "") message(STATUS "Installed files that should not be: ${_file_list}") endif() message(FATAL_ERROR "Install broken") endif() osmium-tool-1.14.0/export-example-config/000077500000000000000000000000001420023413700202725ustar00rootroot00000000000000osmium-tool-1.14.0/export-example-config/default-config.json000066400000000000000000000007101420023413700240520ustar00rootroot00000000000000 { "attributes": { "type": false, "id": false, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "format_options": { }, "linear_tags": true, "area_tags": true, "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/export-example-config/example-config.json000066400000000000000000000007771420023413700240760ustar00rootroot00000000000000{ "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.14.0/extract-example-config/000077500000000000000000000000001420023413700204235ustar00rootroot00000000000000osmium-tool-1.14.0/extract-example-config/README.md000066400000000000000000000012751420023413700217070ustar00rootroot00000000000000 # 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](https://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.14.0/extract-example-config/berlin-feature-collection.geojson000066400000000000000000000076551420023413700270630ustar00rootroot00000000000000{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "name": "Berlin" }, "geometry": { "type": "Polygon", "coordinates": [[ [13.73096, 52.39455], [13.71644, 52.39650], [13.69940, 52.38719], [13.70683, 52.37793], [13.69538, 52.36414], [13.67929, 52.36490], [13.65020, 52.33446], [13.63535, 52.33825], [13.62978, 52.34713], [13.63782, 52.36773], [13.62606, 52.37642], [13.60378, 52.36905], [13.58738, 52.38813], [13.56448, 52.38530], [13.53044, 52.38605], [13.52982, 52.39436], [13.51776, 52.39852], [13.47892, 52.39210], [13.46283, 52.41758], [13.42229, 52.40796], [13.43343, 52.38530], [13.42198, 52.37340], [13.38392, 52.37548], [13.38268, 52.38530], [13.36721, 52.38605], [13.36566, 52.39266], [13.33750, 52.40560], [13.31089, 52.39502], [13.29325, 52.40956], [13.27066, 52.40069], [13.24560, 52.40239], [13.23941, 52.41749], [13.17412, 52.40465], [13.17350, 52.39125], [13.15833, 52.38728], [13.12832, 52.38407], [13.08469, 52.40824], [13.08283, 52.42202], [13.11284, 52.44032], [13.09861, 52.45126], [13.11037, 52.48048], [13.15493, 52.50799], [13.13977, 52.51514], [13.11161, 52.51213], [13.11192, 52.53689], [13.12553, 52.55872], [13.13915, 52.55778], [13.14627, 52.57771], [13.12986, 52.57527], [13.12027, 52.58204], [13.12213, 52.59031], [13.14379, 52.59520], [13.15098, 52.60013], [13.16667, 52.60209], [13.20798, 52.59137], [13.19296, 52.60658], [13.21549, 52.63134], [13.25823, 52.63177], [13.25609, 52.64306], [13.27826, 52.64458], [13.27683, 52.66345], [13.30938, 52.66237], [13.31511, 52.65694], [13.30688, 52.65261], [13.31439, 52.64306], [13.31403, 52.63090], [13.33871, 52.62591], [13.36840, 52.62960], [13.38217, 52.64002], [13.39219, 52.64978], [13.39970, 52.64978], [13.41570, 52.64475], [13.42690, 52.63962], [13.43611, 52.65155], [13.46162, 52.65223], [13.46262, 52.65491], [13.44520, 52.66200], [13.45739, 52.67211], [13.46461, 52.67083], [13.47319, 52.67830], [13.49261, 52.67166], [13.48999, 52.65921], [13.52813, 52.64623], [13.52223, 52.62719], [13.51005, 52.62382], [13.50216, 52.60630], [13.51041, 52.59455], [13.52850, 52.59542], [13.55305, 52.59025], [13.58531, 52.57272], [13.59176, 52.55148], [13.64139, 52.54418], [13.63888, 52.53306], [13.66003, 52.53284], [13.66343, 52.52499], [13.64256, 52.51431], [13.63378, 52.49315], [13.61711, 52.47853], [13.62715, 52.47591], [13.64399, 52.48202], [13.66818, 52.47634], [13.69273, 52.46728], [13.70007, 52.47274], [13.72014, 52.46499], [13.73179, 52.45440], [13.76136, 52.44883], [13.76100, 52.43868], [13.75096, 52.43835], [13.73699, 52.41464], [13.74415, 52.40912], [13.73096, 52.39455] ]] } } ] } osmium-tool-1.14.0/extract-example-config/berlin.geojson000066400000000000000000000075441420023413700232760ustar00rootroot00000000000000{ "type": "Feature", "properties": { "name": "Berlin" }, "geometry": { "type": "Polygon", "coordinates": [[ [13.73096, 52.39455], [13.71644, 52.39650], [13.69940, 52.38719], [13.70683, 52.37793], [13.69538, 52.36414], [13.67929, 52.36490], [13.65020, 52.33446], [13.63535, 52.33825], [13.62978, 52.34713], [13.63782, 52.36773], [13.62606, 52.37642], [13.60378, 52.36905], [13.58738, 52.38813], [13.56448, 52.38530], [13.53044, 52.38605], [13.52982, 52.39436], [13.51776, 52.39852], [13.47892, 52.39210], [13.46283, 52.41758], [13.42229, 52.40796], [13.43343, 52.38530], [13.42198, 52.37340], [13.38392, 52.37548], [13.38268, 52.38530], [13.36721, 52.38605], [13.36566, 52.39266], [13.33750, 52.40560], [13.31089, 52.39502], [13.29325, 52.40956], [13.27066, 52.40069], [13.24560, 52.40239], [13.23941, 52.41749], [13.17412, 52.40465], [13.17350, 52.39125], [13.15833, 52.38728], [13.12832, 52.38407], [13.08469, 52.40824], [13.08283, 52.42202], [13.11284, 52.44032], [13.09861, 52.45126], [13.11037, 52.48048], [13.15493, 52.50799], [13.13977, 52.51514], [13.11161, 52.51213], [13.11192, 52.53689], [13.12553, 52.55872], [13.13915, 52.55778], [13.14627, 52.57771], [13.12986, 52.57527], [13.12027, 52.58204], [13.12213, 52.59031], [13.14379, 52.59520], [13.15098, 52.60013], [13.16667, 52.60209], [13.20798, 52.59137], [13.19296, 52.60658], [13.21549, 52.63134], [13.25823, 52.63177], [13.25609, 52.64306], [13.27826, 52.64458], [13.27683, 52.66345], [13.30938, 52.66237], [13.31511, 52.65694], [13.30688, 52.65261], [13.31439, 52.64306], [13.31403, 52.63090], [13.33871, 52.62591], [13.36840, 52.62960], [13.38217, 52.64002], [13.39219, 52.64978], [13.39970, 52.64978], [13.41570, 52.64475], [13.42690, 52.63962], [13.43611, 52.65155], [13.46162, 52.65223], [13.46262, 52.65491], [13.44520, 52.66200], [13.45739, 52.67211], [13.46461, 52.67083], [13.47319, 52.67830], [13.49261, 52.67166], [13.48999, 52.65921], [13.52813, 52.64623], [13.52223, 52.62719], [13.51005, 52.62382], [13.50216, 52.60630], [13.51041, 52.59455], [13.52850, 52.59542], [13.55305, 52.59025], [13.58531, 52.57272], [13.59176, 52.55148], [13.64139, 52.54418], [13.63888, 52.53306], [13.66003, 52.53284], [13.66343, 52.52499], [13.64256, 52.51431], [13.63378, 52.49315], [13.61711, 52.47853], [13.62715, 52.47591], [13.64399, 52.48202], [13.66818, 52.47634], [13.69273, 52.46728], [13.70007, 52.47274], [13.72014, 52.46499], [13.73179, 52.45440], [13.76136, 52.44883], [13.76100, 52.43868], [13.75096, 52.43835], [13.73699, 52.41464], [13.74415, 52.40912], [13.73096, 52.39455] ]] } } osmium-tool-1.14.0/extract-example-config/berlin.poly000066400000000000000000000066021420023413700226070ustar00rootroot00000000000000berlin 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.14.0/extract-example-config/brandenburg.poly000066400000000000000000000202651420023413700236260ustar00rootroot00000000000000brandenburg 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.14.0/extract-example-config/extracts.json000066400000000000000000000112111420023413700231470ustar00rootroot00000000000000{ "directory": "/tmp/foobar", "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.14.0/extract-example-config/hamburg.poly000066400000000000000000000040571420023413700227630ustar00rootroot00000000000000hamburg 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.14.0/extract-example-config/karlsruhe.osm.bz2000066400000000000000000000404321420023413700236420ustar00rootroot00000000000000BZh61AY&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.14.0/fix-formatting.sh000077500000000000000000000002241420023413700173500ustar00rootroot00000000000000#!/bin/sh # # fix-formatting # exec astyle --style=java --indent-namespaces --indent-switches --pad-header --lineend=linux --suffix=none src/*pp osmium-tool-1.14.0/include/000077500000000000000000000000001420023413700155005ustar00rootroot00000000000000osmium-tool-1.14.0/include/rapidjson/000077500000000000000000000000001420023413700174715ustar00rootroot00000000000000osmium-tool-1.14.0/include/rapidjson/allocators.h000066400000000000000000000241071420023413700220110ustar00rootroot00000000000000// 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.14.0/include/rapidjson/document.h000066400000000000000000003362021420023413700214660ustar00rootroot00000000000000// 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.14.0/include/rapidjson/encodedstream.h000066400000000000000000000246761420023413700224760ustar00rootroot00000000000000// 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.14.0/include/rapidjson/encodings.h000066400000000000000000000676111420023413700216260ustar00rootroot00000000000000// 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.14.0/include/rapidjson/error/000077500000000000000000000000001420023413700206225ustar00rootroot00000000000000osmium-tool-1.14.0/include/rapidjson/error/en.h000066400000000000000000000074361420023413700214070ustar00rootroot00000000000000// 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.14.0/include/rapidjson/error/error.h000066400000000000000000000133001420023413700221210ustar00rootroot00000000000000// 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.14.0/include/rapidjson/filereadstream.h000066400000000000000000000056541420023413700226430ustar00rootroot00000000000000// 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.14.0/include/rapidjson/filewritestream.h000066400000000000000000000061031420023413700230500ustar00rootroot00000000000000// 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.14.0/include/rapidjson/fwd.h000066400000000000000000000077031420023413700204310ustar00rootroot00000000000000// 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.14.0/include/rapidjson/internal/000077500000000000000000000000001420023413700213055ustar00rootroot00000000000000osmium-tool-1.14.0/include/rapidjson/internal/biginteger.h000066400000000000000000000216631420023413700236050ustar00rootroot00000000000000// 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.14.0/include/rapidjson/internal/diyfp.h000066400000000000000000000263701420023413700226010ustar00rootroot00000000000000// 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.14.0/include/rapidjson/internal/dtoa.h000066400000000000000000000177541420023413700224230ustar00rootroot00000000000000// 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.14.0/include/rapidjson/internal/ieee754.h000066400000000000000000000057161420023413700226360ustar00rootroot00000000000000// 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.14.0/include/rapidjson/internal/itoa.h000066400000000000000000000241021420023413700224110ustar00rootroot00000000000000// 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.14.0/include/rapidjson/internal/meta.h000066400000000000000000000146541420023413700224160ustar00rootroot00000000000000// 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.14.0/include/rapidjson/internal/pow10.h000066400000000000000000000070131420023413700224250ustar00rootroot00000000000000// 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.14.0/include/rapidjson/internal/regex.h000066400000000000000000000603711420023413700225770ustar00rootroot00000000000000// 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.14.0/include/rapidjson/internal/stack.h000066400000000000000000000155621420023413700225740ustar00rootroot00000000000000// 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.14.0/include/rapidjson/internal/strfunc.h000066400000000000000000000035511420023413700231460ustar00rootroot00000000000000// 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.14.0/include/rapidjson/internal/strtod.h000066400000000000000000000207401420023413700230000ustar00rootroot00000000000000// 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.14.0/include/rapidjson/internal/swap.h000066400000000000000000000026131420023413700224320ustar00rootroot00000000000000// 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.14.0/include/rapidjson/istreamwrapper.h000066400000000000000000000067701420023413700227210ustar00rootroot00000000000000// 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.14.0/include/rapidjson/memorybuffer.h000066400000000000000000000050001420023413700223370ustar00rootroot00000000000000// 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.14.0/include/rapidjson/memorystream.h000066400000000000000000000051531420023413700223720ustar00rootroot00000000000000// 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.14.0/include/rapidjson/msinttypes/000077500000000000000000000000001420023413700217105ustar00rootroot00000000000000osmium-tool-1.14.0/include/rapidjson/msinttypes/inttypes.h000066400000000000000000000202641420023413700237440ustar00rootroot00000000000000// 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.14.0/include/rapidjson/msinttypes/stdint.h000066400000000000000000000222521420023413700233710ustar00rootroot00000000000000// 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.14.0/include/rapidjson/ostreamwrapper.h000066400000000000000000000044331420023413700227210ustar00rootroot00000000000000// 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.14.0/include/rapidjson/pointer.h000066400000000000000000001621411420023413700213270ustar00rootroot00000000000000// 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.14.0/include/rapidjson/prettywriter.h000066400000000000000000000226011420023413700224270ustar00rootroot00000000000000// 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.14.0/include/rapidjson/rapidjson.h000066400000000000000000000517251420023413700216450ustar00rootroot00000000000000// 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.14.0/include/rapidjson/reader.h000066400000000000000000002336201420023413700211120ustar00rootroot00000000000000// 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.14.0/include/rapidjson/schema.h000066400000000000000000002342161420023413700211120ustar00rootroot00000000000000// 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.14.0/include/rapidjson/stream.h000066400000000000000000000125321420023413700211400ustar00rootroot00000000000000// 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.14.0/include/rapidjson/stringbuffer.h000066400000000000000000000073261420023413700223520ustar00rootroot00000000000000// 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.14.0/include/rapidjson/writer.h000066400000000000000000000553351420023413700211710ustar00rootroot00000000000000// 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.14.0/iwyu.imp000066400000000000000000000024541420023413700155660ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # Configuration for Include-What-You-Use tool # # https://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.14.0/man/000077500000000000000000000000001420023413700146305ustar00rootroot00000000000000osmium-tool-1.14.0/man/CMakeLists.txt000066400000000000000000000063601420023413700173750ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # Create 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}) install(FILES ${_output_file} DESTINATION share/man/man${_section}) set(_source_file ${CMAKE_CURRENT_SOURCE_DIR}/${_name}.md) set(_dest_file ${CMAKE_CURRENT_BINARY_DIR}/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/${PROJECT_VERSION}" --variable "version=${PROJECT_VERSION}" --variable "author=${AUTHOR}" ) 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-create-locations-index) 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-getparents) add_man_page(1 osmium-merge) add_man_page(1 osmium-merge-changes) add_man_page(1 osmium-query-locations-index) add_man_page(1 osmium-removeid) add_man_page(1 osmium-renumber) add_man_page(1 osmium-show) add_man_page(1 osmium-sort) add_man_page(1 osmium-tags-count) 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) add_man_page(5 osmium-output-headers) 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.14.0/man/common-options.md000066400000000000000000000002441420023413700201330ustar00rootroot00000000000000 # 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.14.0/man/input-options.md000066400000000000000000000005441420023413700200050ustar00rootroot00000000000000 # 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.14.0/man/manpage.template000066400000000000000000000012751420023413700200020ustar00rootroot00000000000000$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\-2022 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 https://osmcode.org/contact.html .SH AUTHORS $for(author)$$author$$sep$; $endfor$. $endif$ osmium-tool-1.14.0/man/osmium-add-locations-to-ways.md000066400000000000000000000107041420023413700226050ustar00rootroot00000000000000 # 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 format extension. Most programs reading OSM files will not understand this extension and should ignore the extra data. 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. The command will work with negative IDs (unless the option **--keep-member-nodes** is used). The index types for positive IDs and negative IDs are set separately with the **\--index-type/-i** and **\--index-type-neg** options, respectively. This commands reads its input file(s) only once (unless the **--keep-member-nodes** option is used) and writes its output file in one go so it can be streamed, ie. it can read from STDIN and write to STDOUT. The input file must be sorted in the usual order: first nodes, then ways, then relations, objects of each type ordered by id. If there are multiple input files, they will be read in the order specified on the command line. They must together have the correct order, so, for instance, the first one can have all the sorted nodes, the second all the sorted ways, etc. If this is not the case use **osmium merge** on the inputs first. # OPTIONS -i, \--index-type=TYPE : Set the index type for positive IDs. For details see the **osmium-index-types**(5) man page. \--index-type-neg=TYPE : Set the index type for negative IDs. 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. \--keep-member-nodes : Keep the nodes that are referenced from relations. If this option is specified the input file(s) are read twice. Note that the nodes kept when this option is set are a strict subset of the nodes kept when **--keep-untagged-nodes** is set, so setting both options is unnecessary. \--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-output-headers**(5) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-apply-changes.md000066400000000000000000000077151420023413700212260ustar00rootroot00000000000000 # 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. (If you are using change files of extracts this is not necessarily true and you must specify the change files on the command line in the correct order from oldest to newest. This is because change files from extracts can contain multiple different object versions with the same version and timestamp!) 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/-H** 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. \--redact : Redact (patch) history files. Change files can contain any version of any object which will replace that version of that object from the input. This allows changing the history! This mode is for special use only, for instance to remove copyrighted or private data. -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@ @MAN_PROGRESS_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-merge-changes**(1), **osmium-derive-changes**(1), **osmium-file-formats**(5), **osmium-output-headers**(5) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-cat.md000066400000000000000000000047451420023413700172420ustar00rootroot00000000000000 # 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. Usually this is not the right command to merge two or more typical OSM files, see **osmium merge** for that. # OPTIONS -c, \--clean=ATTR : Clean the attribute (*version*, *timestamp*, *changeset*, *uid*, *user*), from the data before writing it out again. The attribute will be set to 0 (the user will be set to the empty string). This option can be given multiple times. Depending on the output format these attributes might show up as 0 or not show up at all. -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. \--buffer-data : Read all input files into memory and only then write out all the data. This will need a lot of memory and is usually slower than a normal copy. Used for timing the reading and writing phase separately. @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 Remove changeset, uid, and user from a file to protect personal data: osmium cat -c changeset -c uid -c user -o cleaned.osm.pbf data.osm.pbf # SEE ALSO * **osmium**(1), **osmium-file-formats**(5), **osmium-merge**(1), **osmium-output-headers**(5) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-changeset-filter.md000066400000000000000000000043631420023413700217130ustar00rootroot00000000000000 # 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=LONG1,LAT1,LONG2,LAT2 : Only copy changesets with a bounding box overlapping the specified box. The coordinates LONG1,LAT1 are from one arbitrary corner, the coordinates LONG2,LAT2 are from the opposite corner. -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-output-headers**(5) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-check-refs.md000066400000000000000000000042231420023413700204740ustar00rootroot00000000000000 # 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 **\--check-relations/-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 860 MB these days (February 2020). With the **\--check-relations/-r** 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](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-create-locations-index.md000066400000000000000000000040251420023413700230230ustar00rootroot00000000000000 # NAME osmium-create-locations-index - create or update locations index from OSM file # SYNOPSIS **osmium create-locations-index** -i INDEX-FILE \[*OPTIONS*\] *OSM-FILE* # DESCRIPTION Create an index of all node locations from the OSM-FILE in the file INDEX-FILE. If the INDEX-FILE exists, it will not be touched unless the **\--update/-u** option is used. Regardless of the size of the input file, this index will need about 8 * highest-node-id bytes on disk. For a current planet file this is more than 50 GBytes. The index file format is compatible to the one created by "osmium add-location-to-ways -i dense_file_array,INDEX-FILE" and to the flatnode store created by osm2pgsql. When the input file is a full history file or a change file, the last location encountered in the file for any ID ends up in the index. Usually this will be the newest location (from the node with the highest version). This command will not work with negative node IDs. This commands reads its input file only once, so it can be streamed, ie. it can read from STDIN. # OPTIONS -i, \--index-file=FILENAME : The name of the index file. -u, \--update : Allow updating of existing file. @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_OPTIONS@ @MAN_INPUT_OPTIONS@ # DIAGNOSTICS **osmium create-locations-index** 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 create-locations-index** will not use a lot of memory. # EXAMPLES Create node locations index from planet: osmium create-locations-index -i locations.idx planet.osm.pbf Set a node location in the index using an input file in OPL format: echo "n123 x-80.6042 y28.6083" | \ osmium create-locations-index -i locations.idx -F opl --update # SEE ALSO * **osmium**(1), **osmium-query-locations-index**(1), **osmium-file-formats**(5) * [Osmium website](https://osmcode.org/osmium-tool/) * [osm2pgsql](https://wiki.openstreetmap.org/wiki/Osm2pgsql) osmium-tool-1.14.0/man/osmium-derive-changes.md000066400000000000000000000064361420023413700213560ustar00rootroot00000000000000 # 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_PROGRESS_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-output-headers**(5), **osmium-apply-changes**(1), **osmium-diff**(1) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-diff.md000066400000000000000000000070141420023413700173730ustar00rootroot00000000000000 # 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/-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_PROGRESS_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](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-export.md000066400000000000000000000361531420023413700200120ustar00rootroot00000000000000 # 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. Objects with invalid geometries are silently omitted from the output. This is the case for ways with less than two nodes or closed ways or relations that can't be assembled into a valid (multi)polygon. See the options **\--show-errors/-e** and **\--stop-on-error/-E** for how to modify this behaviour. The input file will be read twice (once for the relations, once for nodes and ways), so this command can not read its input from STDIN. This command will not work on full history files. This command will work with negative IDs on OSM objects (for instance on files created with JOSM). # OPTIONS -c, \--config=FILE : Read configuration from specified file. -C, \--print-default-config : Print the default config to STDOUT. Useful if you want to change it and not write the whole thing manually. If you use this option all other options are ignored. -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 https://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. \--geometry-types=TYPES : Specify the geometry types that should be written out. Usually all created geometries (points, linestrings, and (multi)polygons) are written to the output, but you can restrict the types using this option. TYPES is a comma-separated list of the types ("point", "linestring", and "polygon"). -a, \--attributes=ATTRS : In addition to tags, also export attributes specified in this comma-separated list. By default, none are exported. See the **ATTRIBUTES** section below for the known attributes list and an explanation. -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. If you use this options all other options are ignored. -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. THIS OPTION IS DEPRECATED, PLEASE USE "-x print_record_separator=false" INSTEAD. -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). If the input file has negative IDs, this can create IDs such as 'w-12'. In spaten exports the ID is written into the @fid field. For *counter* the value will be an integer, for *type_id* it will be a string. -x, \--format-option=OPTION(=VALUE) : Set an output format option. The options available depend on the output format. See the **OUTPUT FORMAT OPTIONS** section for available options. If the VALUE is not set, the OPTION will be set to "true". If needed you can specify this option multiple times to set several options. Options set on the command line overwrite options set in the config file. @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_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. * `format_options`: An object specifying output format options. The options available depend on the output format. See the **OUTPUT FORMAT OPTIONS** section for available options. These options can also be set using the command line option **\--format-option/-x**. * `linear_tags`: An expression specifying tags that should be treated as linear tags. See below for details and also look at the AREA HANDLING section. * `area_tags`: An expression specifying tags that should be treated as area tags. See below for details and also look at the AREA HANDLING section. * `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 `area_tags` and `linear_tags` can have the following values: true : All tags match. (An empty list `[]` can also be used to mean the same, but this use is deprecated because it can be confusing.) false : No tags match. Array : The array contains one or more expressions as described in the FILTER EXPRESSION section. null : If the `area_tags` or `linear_tags` is set to null or not set at all, the inverse of the other setting is used. So if you do not set the `linear_tags` but have some expressions in `area_tags`, areas will be created for all objects matching those expressions and linestrings for everything else. This can be simpler, because you only have to keep one list, but in cases where an object can be interpreted as both an area and a linestring, only one interpretation will be used. 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 be 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. Another option is to specify attributes list in a comma-separated string for the **\--attributes/-a** command-line option. This way you cannot control column names, but also you won't have to create a config file. Depending on your choice of values for the `attributes` objects, attributes can have the same name as tag keys. If this is the case, the conflicting tag is silently dropped. So if there is a tag "@id=foo" and you have set `id` to `true` in the `attributes` object, the tag will not show up in the output. Note that the `id` is not necessarily unique. Even the combination `type` and `id` is not unique, because a way may end up in the output file as LineString and as (Multi)Polygon. See the **\--add-unique-id/-u** 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 detailed rules: Non-closed way : A non-closed way (with the last node location not the same as the first node location) is always (regardless of any tags) a linestring, not an area. Relation : A relation tagged `type=multipolygon` or `type=boundary` is always (regardless of any tags) assembled into an area. Closed way : For a closed way (with the last node location the same as the first node location) the tags are checked: If the way has an `area=yes` tag, an area is created. If the way has an `area=no` tag, a linestring is created. An `area` tag with a value other than `yes` or `no` is ignored. The configuration settings `area_tags` and `linear_tags` can be used to augment the area check. If any of the tags matches the `area_tags`, an area is created. If any of the tags matches the `linear_tags`, a linestring is created. If both match, an area and a linestring is created. This is important because some objects have tags that make them both, an area and a linestring. # 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. * `pg`: PostgreSQL COPY text format. One line per object containing the WGS84 geometry as WKB, the tags in JSON format and, optionally, more columns for id and attributes. You have to create the table manually, then use the PostgreSQL COPY command to import the data. Enable verbose output to see the SQL commands needed to create the table and load the data. * `spaten`: Spaten, a binary format that is suitable for large data sets. * `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! # OUTPUT FORMAT OPTIONS * `print_record_separator` (default: `true`). Set to `false` to not print the RS (0x1e, record separator) character when using the GeoJSON Text Sequence Format. Ignored for other formats. * `tags_type` (default: `jsonb`). Set to `hstore` to use HSTORE format instead of JSON/JSONB when using the Pg Format. Ignored in other formats. # 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](https://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) * [Spaten Geo Format](https://thomas.skowron.eu/spaten/) osmium-tool-1.14.0/man/osmium-extract.md000066400000000000000000000364551420023413700201500ustar00rootroot00000000000000 # 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/-H** 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=LONG1,LAT1,LONG2,LAT2 : Set the bounding box to cut out. Can not be used with **\--polygon/-p**, **\--config/-c**, or **\--directory/-d**. The coordinates LONG1,LAT1 are from one arbitrary corner, the coordinates LONG2,LAT2 are from the opposite corner. -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. \--clean=ATTR : Clean the attribute (*version*, *timestamp*, *changeset*, *uid*, *user*), from the data before writing it out again. The attribute will be set to 0 (the user will be set to the empty string). This option can be given multiple times. Depending on the output format these attributes might show up as 0 or not show up at all. -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". If you set the value of a file header setting to `null`, the output header will be set to the same header from the input file. "extracts": [ { "output": "hamburg.osm.pbf", "output_format": "pbf", "description": "optional description", "bbox": ... }, { "output": "berlin.osm.pbf", "description": "optional description", "polygon": ... }, { "output": "munich.osm.pbf", "output_header": { "generator": "MyExtractor/1.0", "osmosis_replication_timestamp": null }, "description": "optional description", "multipolygon": ... } ] There are several formats for specifying the regions: **bbox**: A bounding box in one of two formats. The first is a simple array with four real numbers, the first two specifying the coordinates of an arbitrary corner, the second two specifying the coordinates of the opposite corner. { "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 Feature of type Polygon or MultiPolygon, or a FeatureCollection with the first Feature of type Polygon or MultiPolygon. Everything except the actual geometry (of the first Feature) 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 https://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 **complete_ways** strategy you can set the option "-S relations=false" in which case no relations will be written to the output file. 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. The **smart** strategy allows another option "-S complete-partial-relations=X". If this is set, all relations that have more than X percent of their members already in the extract will have their full set of members in the extract. So this allows completing almost complete relations. It can be useful for instance to make sure a boundary relation is complete even if some of it is outside the polygon used for extraction. # 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. If you want to split a large file into many extracts, do this in several steps. First create several larger extracts and then split them again and again into smaller pieces. # 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 extract -p karlsruhe-boundary.osm.bz2 germany-latest.osm.pbf \ -o karlsruhe.osm.pbf Extract the city of Munich using a bounding box: osmium extract -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-output-headers**(5), **osmium-getid**(1), **osmium-merge**(1) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-file-formats.md000066400000000000000000000116221420023413700210530ustar00rootroot00000000000000 # 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. They contain the OSM data from 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 and also deleted objects. 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`=`none`/`zlib`/`lz4` (*default: zlib*) : Set compression type in PBF files. `zlib` (or `true`) is the default and almost all files use this. `none` (or `false`) disables compression which will make writing files a bit faster, but the resulting files are 2 to 3 times bigger. The `lz4` compression is not quite as good as `zlib` but much faster to compress and decompress, it is currently not supported by most OSM file readers. `pbf_compression_level`=... : Set compression level for PBF. Available values and default depend on the compression type used, see the OSM File Formats Manual for details. `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. This can also be set to other values, see the OSM File Formats Manual for details. `locations_on_ways`=`true`/`false` (*default: false*) : Add node locations to way nodes. (PBF, XML, OPL only.) `use_color`=`true`/`false` (*default: false*) : Output with ANSI colors. (DEBUG format only.) `add_crc32`=`true`/`false` (*default: false*) : Add CRC32 checksum to all objects. (DEBUG format only.) # EXAMPLES Here are some examples: `pbf` : PBF format. `pbf,add_metadata=false` : PBF format, don't 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](https://osmcode.org/osmium-tool/) * [OSM File Formats Manual](https://osmcode.org/file-formats-manual/) osmium-tool-1.14.0/man/osmium-fileinfo.md000066400000000000000000000136261420023413700202640ustar00rootroot00000000000000 # 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/-e** option to show more information. Normally this command will output the data in human readable form. If the **\--json/-j** option is used, the output will be in JSON format instead. If the **\--get/-g** option is used, only the value of the named variable will be printed. The output is split into four 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/-e** 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. Metadata : This section shows which metadata attributes are used in the file. It contains information which attributes are used by all objects in the file and which are only used by some objects. This section is only shown if the **\--extended/-e** option was used because the whole file has to be read. This commands reads its input file only once, ie. it can read from STDIN. # OPTIONS -c, \--crc : Calculate the CRC32. This is the default if you use the JSON output format. \--no-crc : Do not calculate the CRC32. This is the default unless you use the JSON output format. -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/-j**. -G, \--show-variables : Show a list of all variable names. -j, \--json : Output in JSON format. Can not be used together with **\--get/-g**. -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. This only takes effect if the **\--extended/-e** option is also used. @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.boxes - STRING (could be multiline) 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 with 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.minid.nodes - INTEGER data.minid.ways - INTEGER data.minid.relations - INTEGER data.minid.changesets - INTEGER data.maxid.nodes - INTEGER data.maxid.ways - INTEGER data.maxid.relations - INTEGER data.maxid.changesets - INTEGER data.buffers.count - INTEGER data.buffers.size - INTEGER data.buffers.capcity - INTEGER metadata.all_objects.version - BOOL (yes|no) metadata.all_objects.timestamp - BOOL (yes|no) metadata.all_objects.changeset - BOOL (yes|no) metadata.all_objects.uid - BOOL (yes|no) metadata.all_objects.user - BOOL (yes|no) metadata.some_objects.version - BOOL (yes|no) metadata.some_objects.timestamp - BOOL (yes|no) metadata.some_objects.changeset - BOOL (yes|no) metadata.some_objects.uid - BOOL (yes|no) metadata.some_objects.user - BOOL (yes|no) All timestamps are in the usual OSM ISO format `yy-mm-ddThh::mm::ssZ`. Boxes are in the format `(xmin, ymin, xmax, ymax)`. There are two variables for each metadata field. The `metadata.all_objects.*` variables are true if all objects in the file have the attribute. The `metadata.some_objects.*` variables are true if at least one object in the file has the attribute. Please note that objects last modified by anonymous users (until 2007) do not have `user` and `uid` attributes and can lead to wrong results. # 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](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-getid.md000066400000000000000000000121151420023413700175550ustar00rootroot00000000000000 # 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 **\--add-referenced/-r** 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 **\--add-referenced/-r** 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 line 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 **\--id-file/-i**) 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 **\--with-history/-H** 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 **\--with-history/-H** 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/-H** 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 **\--id-file/-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. -t, \--remove-tags : Remove tags from objects that are not explicitly requested but are only included to complete references (nodes in ways and members of relations). If an object is both requested and used as a reference it will keep its tags. You also need **\--add-referenced/-r** for this to make sense. \--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 **\--with-history/-H** 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-getparents**(1), **osmium-removeid**(1), **osmium-file-formats**(5), **osmium-output-headers**(5) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-getparents.md000066400000000000000000000105511420023413700206370ustar00rootroot00000000000000 # NAME osmium-getparents - get parents of objects from OSM file # SYNOPSIS **osmium getparents** \[*OPTIONS*\] *OSM-FILE* *ID*...\ **osmium getparents** \[*OPTIONS*\] *OSM-FILE* -i *ID-FILE*\ **osmium getparents** \[*OPTIONS*\] *OSM-FILE* -I *ID-OSM-FILE* # DESCRIPTION Get objects referencing the objects with the specified IDs from the input and write them to the output. So this will get ways referencing any of the specified node IDs and relations referencing any specified node, way, or relation IDs. Only one level of indirection is resolved, so no relations of relations are found and no relations referencing ways referencing the specified node IDs. IDs can be specified 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 **\--add-self/-s** is specified, the objects with the specified IDs themselves will also be added to the output. Objects will be written out in the order they are found in the *OSM-FILE*. The input file is read only once. 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 line 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 **\--id-file/-i**) 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 be a history file, then all matching versions of the objects will be copied to the output. 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. -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. -s, \--add-self : Also add all objects with the specified IDs to the output. \--verbose-ids : Also print all requested 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 getparents** exits with exit code 0 ~ if there was no error. 1 ~ if there was an error processing the data. 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium getparents** does all its work on the fly and only keeps a table of all IDs it needs in main memory. # EXAMPLES Output all ways referencing nodes 17 or 1234, and all relations with nodes 17 or 1234, or way 42, or relation 111 as members to STDOUT in OPL format: osmium getparents -f opl planet.osm.pbf n1234 w42 n17 r111 # SEE ALSO * **osmium**(1), **osmium-getid**(1), **osmium-file-formats**(5), **osmium-output-headers**(5) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-index-types.md000066400000000000000000000046221420023413700207360ustar00rootroot00000000000000 # 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. When using the file-based index types (`*_file_array`), add the filename you want to use for the index after a comma to the index types like so: `... -i dense_file_array,index.dat ...` # 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](https://osmcode.org/osmium-tool/) * [Index types](https://osmcode.org/osmium-concepts/#indexes) osmium-tool-1.14.0/man/osmium-merge-changes.md000066400000000000000000000040431420023413700211670ustar00rootroot00000000000000 # 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. (If you are using change files of extracts this is not necessarily true and you must specify the change files on the command line in the correct order from oldest to newest. This is because change files from extracts can contain multiple different object versions with the same version and timestamp!) 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_PROGRESS_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-output-headers**(5), **osmium-merge**(1) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-merge.md000066400000000000000000000042121420023413700175570ustar00rootroot00000000000000 # 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. # OPTIONS -H, \--with-history : Do not warn when there are multiple versions of the same object in the input files. @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_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-output-headers**(5), **osmium-merge-changes**(1) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-output-headers.md000066400000000000000000000033161420023413700214350ustar00rootroot00000000000000 # NAME osmium-output-headers - Header options that can be set on output files # DESCRIPTION Most osmium commands that write OSM files can set values in the file header of the OSM file using the **\--output-header** option. The format generally is **\--output-header=OPTION=VALUE**. For some commands you can use the special format **\--output-header=OPTION!** (ie. an exclamation mark after the *OPTION* and no value set) to set the value to the same as in the input file. See the individual command man pages for where this is allowed. # HEADER OPTIONS `generator` : Set the "generator program" value. Default is "osmium/VERSION". Can also be set using the **\--generator** option. (XML and PBF files only.) `xml_josm_upload` : Value of the upload attribute on the osm XML element (true or false) for use in JOSM. (XML files only.) `osmosis_replication_timestamp` : Timestamp used in replication (PBF files only). `osmosis_replication_sequence_number` : Sequence number used in replication (PBF files only). `osmosis_replication_base_url` : Base URL for change files used in replication (PBF files only). `sorting` : Set the **Sort.Type_then_ID** property in the PBF header if set to **Type_then_ID**. Other values are currently not supported. (PBF files only). Note that this only sets the header option, it does not actually sort the file! Use **osmium sort** for that. # EXAMPLES Copy the file in.osm.pbf to out.osm.pbf setting the generator to **myscript**: osmium cat --output-header=generator=myscript -o out.osm.pbf in.osm.pbf # SEE ALSO * **osmium**(1) * [Osmium website](https://osmcode.org/osmium-tool/) * [Replication headers](https://wiki.openstreetmap.org/wiki/PBF_Format) osmium-tool-1.14.0/man/osmium-query-locations-index.md000066400000000000000000000036371420023413700227350ustar00rootroot00000000000000 # NAME osmium-query-locations-index - query node locations index # SYNOPSIS **osmium query-locations-index** -i INDEX-FILE \[*OPTIONS*\] *NODE-ID*\ **osmium query-locations-index** -i INDEX-FILE \[*OPTIONS*\] \--dump # DESCRIPTION Get the location of a node from an index created with **osmium create-locations-index** or dump the whole index into an OSM file. The index file format is compatible to the one created by "osmium add-location-to-ways -i dense_file_array,INDEX-FILE" and to the flatnode store created by osm2pgsql. This command will not work with negative node IDs. Note that when the **\--dump** option is used, metadata (like version, timestamp, etc.) is not written to the output file because it is all empty anyway. Use the **\--output-format/-f** option with `add_metadata=...` to overwrite this. # OPTIONS \--dump : Dump all node locations to an OSM file. Use the **\--output/-o** and **\--output-format/-f** options to set the file format to be used. Default is STDOUT and the OPL format, respectively. -i, \--index-file=FILENAME : The name of the index file. @MAN_COMMON_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # DIAGNOSTICS **osmium query-locations-index** exits with exit code 0 ~ if everything went alright and the node location was found, 1 ~ if the node location was not found, 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium query-locations-index** will not use a lot of memory. # EXAMPLES Get location of node 1234 from locations.idx: osmium query-locations-index -i locations.idx 1234 Dump contents of locations.idx into an OPL file: osmium query-locations-index -i locations.idx --dump -o nodes.opl # SEE ALSO * **osmium**(1), **osmium-create-locations-index**(1), **osmium-file-formats**(5), **osmium-output-headers**(5) * [Osmium website](https://osmcode.org/osmium-tool/) * [osm2pgsql](https://wiki.openstreetmap.org/wiki/Osm2pgsql) osmium-tool-1.14.0/man/osmium-removeid.md000066400000000000000000000070301420023413700202730ustar00rootroot00000000000000 # NAME osmium-removeid - remove objects from OSM file by ID # SYNOPSIS **osmium removeid** \[*OPTIONS*\] *OSM-FILE* *ID*...\ **osmium removeid** \[*OPTIONS*\] *OSM-FILE* -i *ID-FILE*\ **osmium removeid** \[*OPTIONS*\] *OSM-FILE* -I *ID-OSM-FILE* # DESCRIPTION Copy input file to output removing objects with the specified IDs. 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. Objects will be written out in the order they are found in the *OSM-FILE*. The input file is only read once, reading from *STDIN* is possible by using the special file name '-'. 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 line 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 **\--id-file/-i**) 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 remove. The *OSM-FILE* can be a history file in which case all versions of the objects with the specified IDs will be removed. 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. -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 **\--id-file/-i** but get the IDs from an OSM file. This option can be used multiple times. @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_OPTIONS@ @MAN_INPUT_OPTIONS@ @MAN_OUTPUT_OPTIONS@ # DIAGNOSTICS **osmium removeid** exits with exit code 0 ~ if nothing went wrong 2 ~ if there was a problem with the command line arguments. # MEMORY USAGE **osmium removeid** does all its work on the fly and only keeps a table of all IDs it needs in main memory. # EXAMPLES Output all nodes except nodes 17 and 1234, all ways except way 42, and all relations except relation 111 to STDOUT in OPL format: osmium removeid -f opl planet.osm.pbf n1234 w42 n17 r111 # SEE ALSO * **osmium**(1), **osmium-getid**(1), **osmium-file-formats**(5), **osmium-output-headers**(5) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-renumber.md000066400000000000000000000120151420023413700202770ustar00rootroot00000000000000 # 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 **\--index-directory/-i** 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. \--show-index=TYPE : Print the content of the index for TYPE (node, way, or relation) on STDOUT. Each line contains the old ID, a space character and then the new ID. Any other options (except **\--index-directory/-i**) are ignored if this option is used. -s, \--start-id=FIRST_ID or FIRST_NODE_ID,FIRST_WAY_ID,FIRST_RELATION_ID : Set the first ID that should be used. If the ID is positive, IDs are counted upwards, if the ID is negative, they are counted downwards. This can be set to either a single ID which is used for all object types or a comma-separated list of three IDs used for the first node, way, and relation, respectively. If this is not set, IDs for all object types start at 1. -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 **\--index-directory/-i** option is specified, index files named `nodes.idx`, `ways.idx`, and `relations.idx` are read from and written to the given directory together with a file called `start_ids` that contains the start IDs set with **\--start-id/-s**. 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 print the indexes in text format using the **\--show-index** option: osmium renumber -i idxdir --show-index node >nodes-index.txt osmium renumber -i idxdir --show-index way >ways-index.txt osmium renumber -i idxdir --show-index relation >relations-index.txt # 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 the about 3.3 GB Germany PBF file currently (February 2020) takes about three minutes and needs about 7 GB RAM. Renumber a PBF file starting the node IDs at 1 (and counting upwards), the way IDs at 100 and the relation IDs at -200 (and counting downwards. osmium renumber -o renumbered.osm.pbf -s 1,100,-200 athens.osm.pbf 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-output-headers**(5), **osmium-sort**(1) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-show.md000066400000000000000000000041201420023413700174360ustar00rootroot00000000000000 # 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 **output-format/-f** 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](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-sort.md000066400000000000000000000043621420023413700174550ustar00rootroot00000000000000 # 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. If there are several objects of the same type and with the same ID and version the sort order is unspecified. 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. (Unless the *multipass* strategy is used.) # OPTIONS -s, \--strategy=STRATEGY : Sorting strategy. The "simple" strategy reads all input files into memory, does the sorting and writes everything out. The "multipass" strategy reads the input files in three passes, one for nodes, one for ways, and one for relations. After reading all objects of each type, they are sorted and written out. This is a bit slower than the "simple" strategy, but uses less memory. The "multipass" strategy doesn't work when reading from STDIN. Default: "simple". @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_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-output-headers**(5) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-tags-count.md000066400000000000000000000114051420023413700205460ustar00rootroot00000000000000 # NAME osmium-tags-count - count keys/tags # SYNOPSIS **osmium tags-count** \[*OPTIONS*\] *OSM-FILE* [*TAG-EXPRESSION*...]\ **osmium tags-count** \[*OPTIONS*\] \--expressions=*FILE* *OSM-FILE* # DESCRIPTION Count how often keys or tags appear in the input file. If the only command line argument is an OSM file, all keys in this file are counted. If there are one or more tag expressions on the command line, only the keys and tags matching those expressions are counted. See the **TAG EXPRESSIONS** section for a description of the expression format. The output has one line per key/tag found. Each line contains the count, the tag key, and the tag value (if matching tags) separated by TAB characters. Tag keys and values are surrounded by double quotes. Any double quotes in the keys and values are doubled. # 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. See the **TAG EXPRESSIONS** section for further details. -m COUNT, \--min-count=COUNT : The minimum count that should be in the output. Used when you are only interested in common keys/tags. -M COUNT, \--max-count=COUNT : The maximum count that should be in the output. Used when you are only interested in rare keys/tags. -s SORT, \--sort=SORT : Sort order. Order by "count-asc", "count-desc", "name-asc", or "name-desc". Default is "count-desc". -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. @MAN_COMMON_OPTIONS@ @MAN_PROGRESS_OPTIONS@ @MAN_INPUT_OPTIONS@ # OUTPUT OPTIONS -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. # TAG EXPRESSIONS A filter expression specifies one or more keys and/or tags that should be counted in the data. Some examples: amenity : Matches the key "amenity". highway=primary : Matches the tag with key "highway" and value "primary". highway!=primary : Matches any tag with key "highway" and a value other than "primary". type=multipolygon,boundary : Matches any tag with key "type" and value "multipolygon" or "boundary". name,name:de=Kastanienallee,Kastanienstrasse : Matches any tag with the key "name" or "name:de" with the value "Kastanienallee" or "Kastanienstrasse". addr:\* : Matches tags with keys starting with "addr:" name=\*Paris : Matches all tags with key "name" and a value that contains the word "Paris". If there is no equal sign ("=") in the expression only keys are matched and values can be 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-count** 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-count** keeps all counters in memory. For a large OSM file and unrestricted keys or, worse, tags, this can use quite a lot of memory. (Counting all tags on a full planet file will use about 16 GByte RAM.) Use the filter expressions to restrict the counting to the keys or tags you are actually interested in. # EXAMPLES Count all keys in Spain and display most common keys first: osmium tags-count spain.osm.pbf Count all building keys in Madrid: osmium tags-count madrid.osm.pbf building Count all building tags on ways in Madrid, order by name: osmium tags-count -t way --sort=name-asc madrid.osm.pbf 'building=*' Count all relation types in Sevilla that appear at least 100 times: osmium tags-count -t relation -m 100 sevilla.osm.pbf 'type=*' Count all tags in the input file. Note that this might need quite a lot of memory! osmium tags-count input.osm.pbf '*=*' # SEE ALSO * **osmium**(1), **osmium-file-formats**(5) * [Osmium website](https://osmcode.org/osmium-tool/) * [Taginfo](https://github.com/taginfo/taginfo/) osmium-tool-1.14.0/man/osmium-tags-filter.md000066400000000000000000000134461420023413700207120ustar00rootroot00000000000000 # 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 at least one of 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 **\--omit-referenced/-R** is used. This applies to nodes referenced in ways and members referenced in relations. If the option **\--omit-referenced/-R** 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 **\--omit-referenced/-R** option is used. The command can not be used on change files. # 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. See 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. -t, \--remove-tags : Remove tags from objects that are not matching the filter expression but are included to complete references (nodes in ways and members of relations). If an object is both matching the filter and used as a reference it will keep its tags. @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), 'r' (for relations), and 'a' (for areas - closed ways with 4 or more nodes and relations with `type=multipolygon` or `type=boundary` tag). 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". a/building : Matches any closed ways with 4 or more nodes or relations tagged "building". Relations must also have a tag "type=multipolygon" or "type=boundary". If there is no equal sign ("=") in the expression only keys are matched and values can be 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. Area matches (with leading "a/") do not check whether the matched object is a valid (multi)polygon, they only check whether an object might possibly be turned into a (multi)polygon. This is the case for all closed ways (where the first and last node are the same) with 4 or more nodes and for all relations that have an additional "type=multipolygon" or "type=boundary" tag. # 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 **\--omit-referenced/-R** 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-output-headers**(5) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium-time-filter.md000066400000000000000000000035151420023413700207060ustar00rootroot00000000000000 # 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_PROGRESS_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-output-headers**(5) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/osmium.md000066400000000000000000000066371420023413700164770ustar00rootroot00000000000000 # 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. This will only work on Linux and OS/X systems and only if the `man` command is available and working correctly. # 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 getparents : get parents of objects from OSM file help : show help about commands merge : merge several OSM files into one merge-changes : merge several OSM change files into one removeid : remove OSM objects with specified IDs 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. On most commands, if you use the **\--verbose/-v** option, osmium will print out the 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/-v** on smaller datasets to get an idea how much memory it needs. On Linux a program that uses a lot of memory can be killed by the kernel without the program being notified. If you see osmium dieing without any apparent reason, this might be the case. Search on the Internet for "OOM killer" to find out more about this. # 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-getparents**(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-index-types**(5), **osmium-output-headers**(5) * [Osmium website](https://osmcode.org/osmium-tool/) osmium-tool-1.14.0/man/output-options.md000066400000000000000000000022101420023413700201760ustar00rootroot00000000000000 # 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=VALUE : Add output header option. This command line option can be used multiple times for different OPTIONs. See the *osmium-output-headers(5)* man page for a list of available header options. For some commands you can use the special format "OPTION!" (ie. an exclamation mark after the OPTION and no value set) to set the value to the same as in the input file. osmium-tool-1.14.0/man/progress-options.md000066400000000000000000000010261420023413700205060ustar00rootroot00000000000000 \--progress : Show progress bar. Usually a progress bar is only displayed if STDOUT and STDERR are detected to be 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 STDOUT and STDERR are 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.14.0/osmium-wrapper.in000077500000000000000000000007531420023413700174040ustar00rootroot00000000000000#!/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.14.0/scripts/000077500000000000000000000000001420023413700155445ustar00rootroot00000000000000osmium-tool-1.14.0/scripts/osm-history-splitter2osmium-extract-config.sh000077500000000000000000000012761420023413700265010ustar00rootroot00000000000000#!/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.14.0/src/000077500000000000000000000000001420023413700146445ustar00rootroot00000000000000osmium-tool-1.14.0/src/CMakeLists.txt000066400000000000000000000007161420023413700174100ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool # #----------------------------------------------------------------------------- add_executable(osmium main.cpp commands.cpp ${PROJECT_BINARY_DIR}/src/version.cpp ${OSMIUM_SOURCE_FILES} ) target_link_libraries(osmium ${Boost_LIBRARIES} ${OSMIUM_LIBRARIES}) set_pthread_on_target(osmium) install(TARGETS osmium DESTINATION bin) osmium-tool-1.14.0/src/cmd.cpp000066400000000000000000000136241420023413700161210ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" #include "exception.hpp" #include #include #include #include #include #include #include po::options_description Command::add_common_options(const 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; } bool 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" << m_command_factory.get_description(name()) << "\n" << desc << "\nUse 'osmium help " << name() << "' to display the manual page.\n"; return false; } if (vm.count("verbose")) { m_vout.verbose(true); } return 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::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"; } } std::string check_index_type(const std::string& index_type_name, bool allow_none) { if (allow_none && index_type_name == "none") { return index_type_name; } std::string type{index_type_name}; const auto pos = type.find(','); if (pos != std::string::npos) { type.resize(pos); } const auto& map_factory = osmium::index::MapFactory::instance(); if (!map_factory.has_map_type(type)) { throw argument_error{"Unknown index type '" + index_type_name + "'. Use --show-index-types or -I to get a list."}; } return index_type_name; } osmium-tool-1.14.0/src/cmd.hpp000066400000000000000000000213601420023413700161220ustar00rootroot00000000000000#ifndef CMD_HPP #define CMD_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "option_clean.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include const char* get_osmium_version() noexcept; const char* get_osmium_long_version() noexcept; const char* get_libosmium_version() noexcept; class CommandFactory; namespace po = boost::program_options; /** * 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: const CommandFactory& m_command_factory; osmium::VerboseOutput m_vout{false}; OptionClean m_clean; public: explicit Command(const CommandFactory& command_factory) : m_command_factory(command_factory) { } 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; static po::options_description add_common_options(bool with_progress = true); bool 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::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_internal() const { switch (m_display_progress) { case display_progress_type::on_tty: return osmium::isatty(1) && osmium::isatty(2); // if STDOUT and STDERR are 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); static po::options_description add_single_input_options(); void show_single_input_arguments(osmium::VerboseOutput& vout); const osmium::io::File& input_file() const { return m_input_file; } /// Is the input file STDIN? bool any_input_is_stdin() const noexcept { return m_input_file.filename().empty(); } }; // 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); static po::options_description add_multiple_inputs_options(); void show_multiple_inputs_arguments(osmium::VerboseOutput& vout); const std::vector& input_files() const { return m_input_files; } /// Is any of the input files STDIN? bool any_input_is_stdin() const noexcept { return std::any_of(m_input_files.cbegin(), m_input_files.cend(), [](const osmium::io::File& file) { return file.filename().empty(); }); } }; // class with_multiple_osm_inputs class CommandWithSingleOSMInput : public Command, public with_single_osm_input { public: explicit CommandWithSingleOSMInput(const CommandFactory& command_factory) : Command(command_factory) { } bool display_progress() const { return display_progress_internal() && !any_input_is_stdin(); } }; // class CommandWithSingleOSMInput class CommandWithMultipleOSMInputs : public Command, public with_multiple_osm_inputs { public: explicit CommandWithMultipleOSMInputs(const CommandFactory& command_factory) : Command(command_factory) { } bool display_progress() const { return display_progress_internal() && !any_input_is_stdin(); } }; // class CommandWithMultipleOSMInputs void init_header(osmium::io::Header& header, const osmium::io::Header& input_header, const std::vector& options); 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); static po::options_description add_output_options(); void show_output_arguments(osmium::VerboseOutput& vout); const osmium::io::File& output_file() const { return m_output_file; } void setup_header(osmium::io::Header& header) const; void setup_header(osmium::io::Header& header, const osmium::io::Header& input_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; public: bool register_command(const std::string& name, const std::string& description, create_command_type&& create_function); // Return a vector with names and descriptions of all commands std::vector> help() const; int max_command_name_length() const; std::string get_description(const std::string& name) const; // 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) const; }; // class CommandFactory void register_commands(CommandFactory& cmd_factory); std::string check_index_type(const std::string& index_type_name, bool allow_none = false); #endif // CMD_HPP osmium-tool-1.14.0/src/cmd_factory.cpp000066400000000000000000000042141420023413700176430ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" #include #include #include #include #include bool CommandFactory::register_command(const std::string& name, const std::string& description, create_command_type&& create_function) { command_info info{description, std::forward(create_function)}; return m_commands.emplace(name, info).second; } std::vector> CommandFactory::help() const { std::vector> commands; for (const auto& cmd : m_commands) { commands.emplace_back(cmd.first, cmd.second.description); } return commands; } int CommandFactory::max_command_name_length() const { osmium::max_op max_width; for (const auto& cmd : m_commands) { max_width.update(static_cast(cmd.first.length())); } return max_width(); } std::string CommandFactory::get_description(const std::string& name) const { const auto it = m_commands.find(name); if (it == m_commands.end()) { return ""; } return it->second.description; } std::unique_ptr CommandFactory::create_command(const std::string& name) const { const auto it = m_commands.find(name); if (it == m_commands.end()) { return std::unique_ptr{}; } return std::unique_ptr{(it->second.create)()}; } osmium-tool-1.14.0/src/command_add_locations_to_ways.cpp000066400000000000000000000207311420023413700234210ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_add_locations_to_ways.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bool CommandAddLocationsToWays::setup(const std::vector& arguments) { 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 for positive IDs") ("index-type-neg", po::value()->default_value(default_index_type), "Index type for negative IDs") ("show-index-types,I", "Show available index types") ("keep-member-nodes", "Keep node members of relations") ("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")) { const auto& map_factory = osmium::index::MapFactory::instance(); 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_pos = check_index_type(vm["index-type"].as()); } if (vm.count("index-type-neg")) { m_index_type_name_neg = check_index_type(vm["index-type-neg"].as()); } if (!setup_common(vm, desc)) { return false; } 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("keep-member-nodes")) { m_keep_member_nodes = true; } if (vm.count("ignore-missing-nodes")) { m_ignore_missing_nodes = true; } // If we keep all nodes anyway, the member nodes don't need special consideration if (m_keep_untagged_nodes && m_keep_member_nodes) { std::cerr << "Warning! Option --keep-member-nodes is unnecessary when --keep-untagged-nodes is set.\n"; m_keep_member_nodes = false; } 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 (for positive ids): " << m_index_type_name_pos << '\n'; m_vout << " index type (for negative ids): " << m_index_type_name_neg << '\n'; m_vout << " keep untagged nodes: " << yes_no(m_keep_untagged_nodes); m_vout << " keep nodes that are relation members: " << yes_no(m_keep_member_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) const { 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) { const auto &node = static_cast(object); if (!node.tags().empty() || m_member_node_ids.get_binary_search(node.positive_id())) { writer(object); } } else { writer(object); } } } } } void CommandAddLocationsToWays::find_member_nodes() { for (const auto& input_file : m_input_files) { osmium::io::Reader reader{input_file, osmium::osm_entity_bits::relation, osmium::io::read_meta::no}; 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::node) { m_member_node_ids.set(member.positive_ref()); } } } } } m_member_node_ids.sort_unique(); } bool CommandAddLocationsToWays::run() { if (m_keep_member_nodes) { m_vout << "Getting all nodes referenced from relations...\n"; find_member_nodes(); m_vout << "Found " << m_member_node_ids.size() << " nodes referenced from relations.\n"; } const auto& map_factory = osmium::index::MapFactory::instance(); auto location_index_pos = map_factory.create_map(m_index_type_name_pos); auto location_index_neg = map_factory.create_map(m_index_type_name_neg); location_handler_type location_handler{*location_index_pos, *location_index_neg}; 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(); } const auto mem = location_index_pos->used_memory() + location_index_neg->used_memory(); m_vout << "About " << show_mbytes(mem) << " 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.14.0/src/command_add_locations_to_ways.hpp000066400000000000000000000047611420023413700234330ustar00rootroot00000000000000#ifndef COMMAND_ADD_LOCATIONS_TO_WAYS_HPP #define COMMAND_ADD_LOCATIONS_TO_WAYS_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include #include #include #include #include #include #include using index_type = osmium::index::map::Map; using location_handler_type = osmium::handler::NodeLocationsForWays; class CommandAddLocationsToWays : public CommandWithMultipleOSMInputs, public with_osm_output { osmium::index::IdSetSmall m_member_node_ids; std::string m_index_type_name_pos; std::string m_index_type_name_neg; bool m_keep_untagged_nodes = false; bool m_keep_member_nodes = false; bool m_ignore_missing_nodes = false; void find_member_nodes(); void copy_data(osmium::ProgressBar& progress_bar, osmium::io::Reader& reader, osmium::io::Writer& writer, location_handler_type& location_handler) const; public: explicit CommandAddLocationsToWays(const CommandFactory& command_factory) : CommandWithMultipleOSMInputs(command_factory) { } 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.14.0/src/command_apply_changes.cpp000066400000000000000000000341461420023413700216730ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_apply_changes.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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)") ("redact", "Redact (patch) OSM files") ("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); if (!setup_common(vm, desc)) { return false; } setup_progress(vm); 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()) { if (m_locations_on_ways) { throw argument_error{"Can not use --locations-on-ways on history files."}; } 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("redact")) { if (m_locations_on_ways) { throw argument_error{"Can not use --redact and --locations-on-ways together."}; } m_with_history = true; m_redact = true; m_output_file.set_has_multiple_object_versions(true); } 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::ReaderWithProgressBar reader{display_progress(), 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()); m_vout << "Applying changes and writing them to output...\n"; const auto input = osmium::io::make_input_iterator_range(reader); auto out = osmium::io::make_output_iterator(writer); if (m_redact) { std::set_union(objects.begin(), objects.end(), input.begin(), input.end(), out, osmium::object_order_type_id_version_without_timestamp()); } else { 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"; // This is needed for a special case: When change files have been // created from extracts it is possible that they contain objects // with the same type, id, version, and timestamp. In that case we // still want to get the last object available. So we have to make // sure it appears first in the objects vector before doing the // stable sort. std::reverse(objects.ptr_begin(), objects.ptr_end()); 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; while (osmium::memory::Buffer buffer = reader.read()) { 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; } } else { m_vout << "Applying changes and writing them to output...\n"; const auto input = osmium::io::make_input_iterator_range(reader); auto output_it = boost::make_function_output_iterator(copy_first_with_id(&writer)); 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.14.0/src/command_apply_changes.hpp000066400000000000000000000034051420023413700216720ustar00rootroot00000000000000#ifndef COMMAND_APPLY_CHANGES_HPP #define COMMAND_APPLY_CHANGES_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include class CommandApplyChanges : public CommandWithSingleOSMInput, 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; bool m_redact = false; public: explicit CommandApplyChanges(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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.14.0/src/command_cat.cpp000066400000000000000000000172031420023413700176200ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_cat.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include 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)") ("clean,c", po::value>(), "Clean attribute (version, changeset, timestamp, uid, user)") ("buffer-data", "Buffer all data in memory before writing it out") ; 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 (!setup_common(vm, desc)) { return false; } setup_progress(vm); setup_object_type_nwrc(vm); setup_input_files(vm); setup_output_file(vm); m_clean.setup(vm); if (vm.count("buffer-data")) { m_buffer_data = true; } 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); m_vout << " attributes to clean: " << m_clean.to_string() << '\n'; } void CommandCat::copy(osmium::ProgressBar& progress_bar, osmium::io::Reader& reader, osmium::io::Writer& writer) const { while (osmium::memory::Buffer buffer = reader.read()) { progress_bar.update(reader.offset()); m_clean.apply_to(buffer); writer(std::move(buffer)); } } std::size_t CommandCat::read_buffers(osmium::ProgressBar& progress_bar, osmium::io::Reader& reader, std::vector& buffers) { std::size_t size = 0; while (osmium::memory::Buffer buffer = reader.read()) { progress_bar.update(reader.offset()); m_clean.apply_to(buffer); size += buffer.committed(); buffers.emplace_back(std::move(buffer)); } return size; } void CommandCat::write_buffers(osmium::ProgressBar& progress_bar, std::vector& buffers, osmium::io::Writer& writer) { std::size_t size = 0; for (auto&& buffer : buffers) { size += buffer.committed(); writer(std::move(buffer)); progress_bar.update(size); } } static void report_filename(osmium::VerboseOutput* vout, const osmium::io::File& file, const osmium::io::Reader& reader) { assert(vout); const auto size = reader.file_size(); const auto& name = file.filename(); if (size == 0) { if (name.empty()) { *vout << "Reading from stdin...\n"; } else { *vout << "Reading input file '" << name << "'...\n"; } } else { *vout << "Reading input file '" << name << "' (" << size << " bytes)...\n"; } } bool CommandCat::run() { std::size_t file_size = 0; if (m_input_files.size() == 1) { // single input file osmium::io::Reader reader{m_input_files[0], osm_entity_bits()}; osmium::io::Header header{reader.header()}; report_filename(&m_vout, m_input_files[0], reader); setup_header(header); osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; if (m_buffer_data) { std::vector buffers; osmium::ProgressBar progress_bar_reader{reader.file_size(), display_progress()}; std::size_t size = read_buffers(progress_bar_reader, reader, buffers); progress_bar_reader.done(); m_vout << "All data read.\n"; show_memory_used(); m_vout << "Writing data...\n"; osmium::ProgressBar progress_bar_writer{size, display_progress()}; write_buffers(progress_bar_writer, buffers, writer); progress_bar_writer.done(); } else { osmium::ProgressBar progress_bar{reader.file_size(), display_progress()}; copy(progress_bar, reader, writer); progress_bar.done(); } file_size = 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}; if (m_buffer_data) { std::vector buffers; std::size_t size = 0; osmium::ProgressBar progress_bar_reader{file_size_sum(m_input_files), display_progress()}; for (const auto& input_file : m_input_files) { progress_bar_reader.remove(); osmium::io::Reader reader{input_file, osm_entity_bits()}; report_filename(&m_vout, input_file, reader); size += read_buffers(progress_bar_reader, reader, buffers); progress_bar_reader.file_done(reader.file_size()); reader.close(); } progress_bar_reader.done(); m_vout << "All data read.\n"; show_memory_used(); m_vout << "Writing data...\n"; osmium::ProgressBar progress_bar_writer{size, display_progress()}; write_buffers(progress_bar_writer, buffers, writer); file_size = writer.close(); progress_bar_writer.done(); } else { osmium::ProgressBar progress_bar{file_size_sum(m_input_files), display_progress()}; for (const auto& input_file : m_input_files) { progress_bar.remove(); osmium::io::Reader reader{input_file, osm_entity_bits()}; report_filename(&m_vout, input_file, reader); copy(progress_bar, reader, writer); progress_bar.file_done(reader.file_size()); reader.close(); } file_size = writer.close(); progress_bar.done(); } } if (file_size > 0) { m_vout << "Wrote " << file_size << " bytes.\n"; } show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.14.0/src/command_cat.hpp000066400000000000000000000037751420023413700176360ustar00rootroot00000000000000#ifndef COMMAND_CAT_HPP #define COMMAND_CAT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include #include #include #include class CommandCat : public CommandWithMultipleOSMInputs, public with_osm_output { bool m_buffer_data = false; void copy(osmium::ProgressBar& progress_bar, osmium::io::Reader& reader, osmium::io::Writer& writer) const; std::size_t read_buffers(osmium::ProgressBar& progress_bar, osmium::io::Reader& reader, std::vector& buffers); void write_buffers(osmium::ProgressBar& progress_bar, std::vector& buffers, osmium::io::Writer& writer); public: explicit CommandCat(const CommandFactory& command_factory) : CommandWithMultipleOSMInputs(command_factory) { } 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.14.0/src/command_changeset_filter.cpp000066400000000000000000000203431420023413700223560ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_changeset_filter.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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); if (!setup_common(vm, desc)) { return false; } 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.14.0/src/command_changeset_filter.hpp000066400000000000000000000041051420023413700223610ustar00rootroot00000000000000#ifndef COMMAND_CHANGESET_FILTER_HPP #define COMMAND_CHANGESET_FILTER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include #include #include #include class CommandChangesetFilter : public CommandWithSingleOSMInput, public with_osm_output { std::string m_user; osmium::Box m_box; osmium::Timestamp m_after = osmium::start_of_time(); osmium::Timestamp m_before = osmium::end_of_time(); osmium::user_id_type m_uid = 0; 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; public: explicit CommandChangesetFilter(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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.14.0/src/command_check_refs.cpp000066400000000000000000000247071420023413700211540ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_check_refs.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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); if (!setup_common(vm, desc)) { return false; } 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::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::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) { assert(vout); assert(progress_bar); } uint64_t node_count() const noexcept { return m_node_count; } uint64_t way_count() const noexcept { return m_way_count; } uint64_t relation_count() const noexcept { return m_relation_count; } uint64_t missing_nodes_in_ways() const noexcept { return m_missing_nodes_in_ways; } uint64_t missing_nodes_in_relations() const noexcept { return m_missing_nodes_in_relations; } uint64_t missing_ways_in_relations() const noexcept { return m_missing_ways_in_relations; } uint64_t missing_relations_in_relations() const noexcept { 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() const noexcept { 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: " << show_mbytes(handler.used_memory()) << " MBytes\n"; show_memory_used(); m_vout << "Done.\n"; return handler.no_errors(); } osmium-tool-1.14.0/src/command_check_refs.hpp000066400000000000000000000031151420023413700211470ustar00rootroot00000000000000#ifndef COMMAND_CHECK_REFS_HPP #define COMMAND_CHECK_REFS_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include class CommandCheckRefs : public CommandWithSingleOSMInput { bool m_show_ids = false; bool m_check_relations = false; public: explicit CommandCheckRefs(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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.14.0/src/command_create_locations_index.cpp000066400000000000000000000105711420023413700235570ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_create_locations_index.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bool CommandCreateLocationsIndex::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("index-file,i", po::value(), "Index file name (required)") ("update,u", "Update existing index file") ; 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); if (!setup_common(vm, desc)) { return false; } setup_progress(vm); setup_input_file(vm); if (vm.count("index-file")) { m_index_file_name = vm["index-file"].as(); } else { throw argument_error{"Missing --index-file,-i option."}; } if (vm.count("update")) { m_update = true; } return true; } void CommandCreateLocationsIndex::show_arguments() { show_single_input_arguments(m_vout); m_vout << " other options:\n"; m_vout << " index file: " << m_index_file_name << '\n'; m_vout << " allow update of existing index file: " << yes_no(m_update); } bool CommandCreateLocationsIndex::run() { int flags = O_RDWR | O_CREAT; // NOLINT(hicpp-signed-bitwise) if (!m_update) { flags |= O_EXCL; // NOLINT(hicpp-signed-bitwise) } #ifdef _WIN32 flags |= O_BINARY; // NOLINT(hicpp-signed-bitwise) #endif const int fd = ::open(m_index_file_name.c_str(), flags, 0666); if (fd == -1) { if (errno == EEXIST) { throw argument_error{"Index file exists and you haven't specified --update/-u."}; } throw std::system_error{errno, std::system_category(), std::string("Can not open index file '") + m_index_file_name + "'"}; } osmium::index::map::DenseFileArray location_index{fd}; m_vout << "Reading input file '" << m_input_file.filename() << "'\n"; osmium::io::Reader reader{m_input_file, osmium::osm_entity_bits::node}; osmium::ProgressBar progress_bar{reader.file_size(), display_progress()}; while (const auto buffer = reader.read()) { progress_bar.update(reader.offset()); osmium::apply(buffer, [&](const osmium::Node& node) { location_index.set(node.positive_id(), node.location()); }); } progress_bar.done(); reader.close(); m_vout << "About " << (location_index.used_memory() / (1024LLU * 1024LLU * 1024LLU)) << " GBytes used for node location index on disk.\n"; m_vout << "Done.\n"; return true; } osmium-tool-1.14.0/src/command_create_locations_index.hpp000066400000000000000000000032601420023413700235610ustar00rootroot00000000000000#ifndef COMMAND_CREATE_LOCATIONS_INDEX_HPP #define COMMAND_CREATE_LOCATIONS_INDEX_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include class CommandCreateLocationsIndex : public CommandWithSingleOSMInput { std::string m_index_file_name; bool m_update = false; public: explicit CommandCreateLocationsIndex(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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 "create-locations-index"; } const char* synopsis() const noexcept override final { return "osmium create-locations-index -i INDEX-FILE [OPTIONS] OSM-FILE"; } }; // class CommandCreateLocationsIndex #endif // COMMAND_CREATE_LOCATIONS_INDEX_HPP osmium-tool-1.14.0/src/command_derive_changes.cpp000066400000000000000000000147011420023413700220170ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_derive_changes.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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); if (!setup_common(vm, desc)) { return false; } setup_progress(vm); 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; // NOLINT(google-build-using-namespace) if (object.type() == osmium::item_type::node) { osmium::builder::add_node(m_buffer, _deleted(), _id(object.id()), _version(object.version()), _timestamp(object.timestamp()) ); } else if (object.type() == osmium::item_type::way) { osmium::builder::add_way(m_buffer, _deleted(), _id(object.id()), _version(object.version()), _timestamp(object.timestamp()) ); } else if (object.type() == osmium::item_type::relation) { osmium::builder::add_relation(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::ReaderWithProgressBar reader2{display_progress(), 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(); reader2.progress_bar().remove(); 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}; reader2.progress_bar().remove(); 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.14.0/src/command_derive_changes.hpp000066400000000000000000000036351420023413700220300ustar00rootroot00000000000000#ifndef COMMAND_DERIVE_CHANGES_HPP #define COMMAND_DERIVE_CHANGES_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include #include #include #include class CommandDeriveChanges : public CommandWithMultipleOSMInputs, 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: explicit CommandDeriveChanges(const CommandFactory& command_factory) : CommandWithMultipleOSMInputs(command_factory) { } 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.14.0/src/command_diff.cpp000066400000000000000000000254321420023413700177640ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_diff.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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); if (!setup_common(vm, desc)) { return false; } setup_progress(vm); 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.empty() && (m_output_filename.empty() || 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: OutputAction() noexcept = default; virtual ~OutputAction() noexcept = default; OutputAction(const OutputAction&) = delete; OutputAction& operator=(const OutputAction&) = delete; OutputAction(OutputAction&&) noexcept = delete; OutputAction& operator=(OutputAction&&) noexcept = delete; virtual void left(const osmium::OSMObject& /* object */) { } virtual void right(const osmium::OSMObject& /* object */) { } virtual void same(const osmium::OSMObject& /* object */) { } virtual void different(const osmium::OSMObject& /* left */, const 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(const osmium::OSMObject& object) override { print('-', object); } void right(const osmium::OSMObject& object) override { print('+', object); } void same(const osmium::OSMObject& object) override { print(' ', object); } void different(const osmium::OSMObject& left, const 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(const osmium::OSMObject& object) override { m_writer(object); } void right(const osmium::OSMObject& object) override { m_writer(object); } void same(const osmium::OSMObject& object) override { m_writer(object); } void different(const osmium::OSMObject& left, const 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::ReaderWithProgressBar reader2{display_progress(), 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 = std::make_unique(fd); } else if (m_output_action == "osm") { m_output_file.set("diff"); action = std::make_unique(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 (it2 == end2) { it1->set_diff(osmium::diff_indicator_type::left); ++count_left; if (action) { action->left(*it1); } ++it1; } else if (it1 == end1 || *it2 < *it1) { it2->set_diff(osmium::diff_indicator_type::right); ++count_right; if (action) { action->right(*it2); } ++it2; } else if (*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.14.0/src/command_diff.hpp000066400000000000000000000031511420023413700177630ustar00rootroot00000000000000#ifndef COMMAND_DIFF_HPP #define COMMAND_DIFF_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include class CommandDiff : public CommandWithMultipleOSMInputs, public with_osm_output { std::string m_output_action; bool m_show_summary = false; bool m_suppress_common = false; public: explicit CommandDiff(const CommandFactory& command_factory) : CommandWithMultipleOSMInputs(command_factory) { } 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.14.0/src/command_export.cpp000066400000000000000000000575101420023413700203770ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_export.hpp" #include "exception.hpp" #include "util.hpp" #include "export/export_format_json.hpp" #include "export/export_format_pg.hpp" #include "export/export_format_spaten.hpp" #include "export/export_format_text.hpp" #include "export/export_handler.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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_attributes(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"); } void CommandExport::parse_format_options(const rapidjson::Value& options) { if (!options.IsObject()) { throw config_error{"'format_options' member must be an object."}; } for (const auto& kv : options.GetObject()) { const auto type = kv.value.GetType(); const char* key = kv.name.GetString(); switch (type) { case rapidjson::kNullType: m_options.format_options.set(key, false); break; case rapidjson::kTrueType: m_options.format_options.set(key, true); break; case rapidjson::kFalseType: m_options.format_options.set(key, false); break; case rapidjson::kObjectType: throw config_error{"Option value for key '" + std::string(key) + "' can not be of type object."}; case rapidjson::kArrayType: throw config_error{"Option value for key '" + std::string(key) + "' can not be an array."}; break; case rapidjson::kStringType: m_options.format_options.set(key, kv.value.GetString()); break; case rapidjson::kNumberType: m_options.format_options.set(key, std::to_string(kv.value.GetInt64())); break; } } } static Ruleset parse_tags_ruleset(const rapidjson::Value& object, const char* key) { Ruleset ruleset; const auto json = object.FindMember(key); if (json == object.MemberEnd() || json->value.IsNull()) { // When this is not set, the default is "other". This is later // changed to "any" if both linear_tags and area_tags are missing. ruleset.set_rule_type(tags_filter_rule_type::other); return ruleset; } if (json->value.IsFalse()) { ruleset.set_rule_type(tags_filter_rule_type::none); return ruleset; } if (json->value.IsTrue()) { ruleset.set_rule_type(tags_filter_rule_type::any); return ruleset; } if (!json->value.IsArray()) { throw config_error{std::string{"'"} + key + "' member in top-level object must be false, true, null, or an array."}; } if (json->value.GetArray().Empty()) { std::cerr << "Warning! An empty array for 'linear_tags' or 'area_tags' matches any tags.\n" << " Please use 'true' instead of the array.\n"; ruleset.set_rule_type(tags_filter_rule_type::any); return ruleset; } ruleset.set_rule_type(tags_filter_rule_type::list); 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') { ruleset.add_rule(value.GetString()); } } return ruleset; } 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_attributes(json_attr->value); } const auto json_opts = doc.FindMember("format_options"); if (json_opts != doc.MemberEnd()) { parse_format_options(json_opts->value); } m_linear_ruleset = parse_tags_ruleset(doc, "linear_tags"); m_area_ruleset = parse_tags_ruleset(doc, "area_tags"); if (m_linear_ruleset.rule_type() == tags_filter_rule_type::other && m_area_ruleset.rule_type() == tags_filter_rule_type::other) { m_linear_ruleset.set_rule_type(tags_filter_rule_type::any); m_area_ruleset.set_rule_type(tags_filter_rule_type::any); } 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 = static_cast(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) { 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") ("format-option,x", po::value>(), "Output format options") ("fsync", "Call fsync after writing file") ("geometry-types", po::value(), "Geometry types that should be written (default: 'point,linestring,polygon')") ("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") ("print-default-config,C", "Print default config on STDOUT") ("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") ("attributes,a", po::value(), "Comma-separated list of attributes to add to the output (default: none)") ("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("print-default-config")) { std::cout << R"({ "attributes": { "type": false, "id": false, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "format_options": { }, "linear_tags": true, "area_tags": true, "exclude_tags": [], "include_tags": [] } )"; return false; } if (vm.count("show-index-types")) { const auto& map_factory = osmium::index::MapFactory::instance(); for (const auto& map_type : map_factory.map_types()) { std::cout << map_type << '\n'; } std::cout << "none\n"; return false; } if (!setup_common(vm, desc)) { return false; } setup_progress(vm); setup_input_file(vm); 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 != "pg" && m_output_format != "text" && m_output_format != "spaten") { throw argument_error{"Set output format with --output-format or -f to 'geojson', 'geojsonseq', 'pg', 'spaten', or 'text'."}; } // Set defaults for output format options depending on output format if (m_output_format == "geojsonseq") { m_options.format_options.set("print_record_separator", true); } if (m_output_format == "pg") { m_options.format_options.set("tags_type", "json"); } 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("geometry-types")) { m_geometry_types.clear(); const auto types = osmium::split_string(vm["geometry-types"].as(), ','); for (const auto& type : types) { if (type == "point") { m_geometry_types.point = true; } else if (type == "linestring") { m_geometry_types.linestring = true; } else if (type == "polygon") { m_geometry_types.polygon = true; } else if (type == "multipolygon") { m_geometry_types.polygon = true; } else { throw argument_error{"Unknown geometry type in --geometry-types option: " + type + "."}; } } if (m_geometry_types.empty()) { throw argument_error{"No geometry types in --geometry-types option."}; } } if (vm.count("attributes")) { const auto attrs = osmium::split_string(vm["attributes"].as(), ','); for (const auto& attr : attrs) { if (attr == "type") { m_options.type = "@type"; } else if (attr == "id") { m_options.id = "@id"; } else if (attr == "version") { m_options.version = "@version"; } else if (attr == "changeset") { m_options.changeset = "@changeset"; } else if (attr == "timestamp") { m_options.timestamp = "@timestamp"; } else if (attr == "uid") { m_options.uid = "@uid"; } else if (attr == "user") { m_options.user = "@user"; } else if (attr == "way_nodes") { m_options.way_nodes = "@way_nodes"; } else { throw argument_error{"Unknown attribute in --attributes option: " + attr + "."}; } } } if (vm.count("index-type")) { m_index_type_name = check_index_type(vm["index-type"].as(), true); } if (vm.count("keep-untagged")) { m_options.keep_untagged = true; } if (vm.count("overwrite")) { m_output_overwrite = osmium::io::overwrite::allow; } if (vm.count("format-option")) { for (const auto& str : vm["format-option"].as>()) { m_options.format_options.set(str); } } if (vm.count("omit-rs")) { m_options.format_options.set("print_record_separator", false); warning("The --omit-rs/-r option is deprecated. Please use '-x print_record_separator=false' instead.\n"); 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); } if (m_input_file.filename().empty()) { throw config_error{"Can not read from STDIN, because input file has to be read twice."}; } return true; } static void print_taglist(osmium::VerboseOutput* vout, const std::vector& strings) { assert(vout); for (const auto& str : strings) { *vout << " " << str << '\n'; } } static void print_ruleset(osmium::VerboseOutput* vout, const Ruleset& ruleset) { assert(vout); switch (ruleset.rule_type()) { case tags_filter_rule_type::none: *vout << "none\n"; break; case tags_filter_rule_type::any: *vout << "any\n"; break; case tags_filter_rule_type::list: *vout << "one of the following:\n"; print_taglist(vout, ruleset.tags()); break; case tags_filter_rule_type::other: *vout << "if other tag list doesn't match\n"; break; } } 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'; 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'; if (!m_options.format_options.empty()) { m_vout << " output format options:\n"; for (const auto& option : m_options.format_options) { m_vout << " " << option.first << " = " << option.second << '\n'; } } m_vout << " linear tags: "; print_ruleset(&m_vout, m_linear_ruleset); m_vout << " area tags: "; print_ruleset(&m_vout, m_area_ruleset); 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::make_unique(output_format, output_filename, overwrite, fsync, options); } if (output_format == "pg") { return std::make_unique(output_format, output_filename, overwrite, fsync, options); } if (output_format == "text") { return std::make_unique(output_format, output_filename, overwrite, fsync, options); } if (output_format == "spaten") { return std::make_unique(output_format, output_filename, overwrite, fsync, options); } throw argument_error{"Unknown output format"}; } bool CommandExport::run() { auto handler = create_handler(m_output_format, m_output_filename, m_output_overwrite, m_fsync, m_options); if (m_vout.verbose()) { handler->debug_output(m_vout, m_output_filename); } osmium::area::Assembler::config_type assembler_config; osmium::area::MultipolygonManager mp_manager{assembler_config}; m_vout << "First pass (of two) 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 (of two) through input file...\n"; m_linear_ruleset.init_filter(); m_area_ruleset.init_filter(); ExportHandler export_handler{std::move(handler), m_linear_ruleset, m_area_ruleset, m_geometry_types, m_show_errors, m_stop_on_error}; osmium::handler::CheckOrder check_order_handler; if (m_index_type_name == "none") { osmium::io::ReaderWithProgressBar reader{display_progress(), 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_pos = map_factory.create_map(m_index_type_name); auto location_index_neg = map_factory.create_map(m_index_type_name); location_handler_type location_handler{*location_index_pos, *location_index_neg}; if (!m_stop_on_error) { location_handler.ignore_errors(); } osmium::io::ReaderWithProgressBar reader{display_progress(), 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 " << show_mbytes(location_index_pos->used_memory() + location_index_neg->used_memory()) << " MBytes used for node location index (in main memory or on disk).\n"; } if (m_stop_on_error) { const auto incomplete_relations = mp_manager.relations_database().count_relations(); if (incomplete_relations > 0) { throw osmium::geometry_error{"Found " + std::to_string(incomplete_relations) + " incomplete relation(s)"}; } } 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.14.0/src/command_export.hpp000066400000000000000000000051771420023413700204060ustar00rootroot00000000000000#ifndef COMMAND_EXPORT_HPP #define COMMAND_EXPORT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include "export/options.hpp" #include "export/ruleset.hpp" #include #include #include #include #include #include class CommandExport : public CommandWithSingleOSMInput { using index_type = osmium::index::map::Map; using location_handler_type = osmium::handler::NodeLocationsForWays; options_type m_options{}; Ruleset m_linear_ruleset; Ruleset m_area_ruleset; 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; geometry_types m_geometry_types; 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_attributes(const rapidjson::Value& attributes); void parse_format_options(const rapidjson::Value& options); void parse_config_file(); public: explicit CommandExport(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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.14.0/src/command_extract.cpp000066400000000000000000000565211420023413700205310ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "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" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN // Prevent winsock.h inclusion; avoid winsock2.h conflict # endif # include #endif #ifndef _MSC_VER # include #endif static osmium::Box parse_bbox(const rapidjson::Value& value) { if (value.IsArray()) { if (value.Size() != 4) { throw config_error{"'bbox' must be an array with exactly four elements."}; } if (!value[0].IsNumber() || !value[1].IsNumber() || !value[2].IsNumber() || !value[3].IsNumber()) { throw config_error{"'bbox' array elements must be numbers."}; } const auto value0 = value[0].GetDouble(); const auto value1 = value[1].GetDouble(); const auto value2 = value[2].GetDouble(); const auto value3 = value[3].GetDouble(); if (value0 < -180.0 || value0 > 180.0) { throw config_error{"Invalid coordinate in bbox: " + std::to_string(value0) + "."}; } if (value1 < -90.0 || value1 > 90.0) { throw config_error{"Invalid coordinate in bbox: " + std::to_string(value1) + "."}; } if (value2 < -180.0 || value2 > 180.0) { throw config_error{"Invalid coordinate in bbox: " + std::to_string(value2) + "."}; } if (value3 < -90.0 || value3 > 90.0) { throw config_error{"Invalid coordinate in bbox: " + std::to_string(value3) + "."}; } const osmium::Location location1{value0, value1}; const osmium::Location location2{value2, value3}; osmium::Box box; box.extend(location1); box.extend(location2); return box; } 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 auto left_value = left->value.GetDouble(); const auto bottom_value = bottom->value.GetDouble(); const auto right_value = right->value.GetDouble(); const auto top_value = top->value.GetDouble(); if (left_value < -180.0 || left_value > 180.0) { throw config_error{"Invalid coordinate in bbox: " + std::to_string(left_value) + "."}; } if (right_value < -180.0 || right_value > 180.0) { throw config_error{"Invalid coordinate in bbox: " + std::to_string(right_value) + "."}; } if (top_value < -90.0 || top_value > 90.0) { throw config_error{"Invalid coordinate in bbox: " + std::to_string(top_value) + "."}; } if (bottom_value < -90.0 || bottom_value > 90.0) { throw config_error{"Invalid coordinate in bbox: " + std::to_string(bottom_value) + "."}; } const osmium::Location bottom_left{left_value, bottom_value}; const osmium::Location top_right{right_value, top_value}; 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."}; } static std::size_t parse_multipolygon_object(const std::string& directory, std::string file_name, std::string file_type, osmium::memory::Buffer* buffer) { assert(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()) { if (ends_with(file_name, ".poly")) { file_type = "poly"; } else if (ends_with(file_name, ".json") || ends_with(file_name, ".geojson")) { file_type = "geojson"; } else { std::string suffix{get_filename_suffix(file_name)}; 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.empty()) { 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'"}; } static std::size_t parse_multipolygon_object(const std::string& directory, const rapidjson::Value& value, osmium::memory::Buffer* buffer) { assert(buffer); const std::string file_name{get_value_as_string(value, "file_name")}; const std::string file_type{get_value_as_string(value, "file_type")}; return parse_multipolygon_object(directory, file_name, file_type, buffer); } static std::size_t parse_polygon(const std::string& directory, const rapidjson::Value& value, osmium::memory::Buffer* buffer) { assert(buffer); if (value.IsArray()) { return parse_polygon_array(value, buffer); } 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) { assert(buffer); if (value.IsArray()) { return parse_multipolygon_array(value, buffer); } if (value.IsObject()) { return parse_multipolygon_object(directory, value, buffer); } throw config_error{"Multipolygon must be an object or array."}; } static bool is_existing_directory(const char* name) { #ifdef _MSC_VER // Windows implementation // https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx struct _stat64 s{}; if (::_stati64(name, &s) != 0) { return false; } return (s.st_mode & _S_IFDIR) != 0; #else // Unix implementation struct stat s; // NOLINT clang-tidy if (::stat(name, &s) != 0) { return false; } return S_ISDIR(s.st_mode); // NOLINT(hicpp-signed-bitwise) #endif } void CommandExtract::set_directory(const std::string& directory) { if (!is_existing_directory(directory.c_str())) { throw config_error{"Output directory is missing or not accessible: " + 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.push_back(std::make_unique(output_file, description, parse_bbox(json_bbox->value))); } else if (json_polygon != e.MemberEnd()) { m_extracts.push_back(std::make_unique(output_file, description, m_buffer, parse_polygon(m_config_directory, json_polygon->value, &m_buffer))); } else if (json_multipolygon != e.MemberEnd()) { m_extracts.push_back(std::make_unique(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.IsNull()) { extract.add_header_option(it->name.GetString()); } else { if (!member_value.IsString()) { throw config_error{"Values in 'output_header' object must be strings or null."}; } 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."}; } return std::make_unique(m_extracts, m_options); } if (name == "complete_ways") { if (m_with_history) { return std::make_unique(m_extracts, m_options); } return std::make_unique(m_extracts, m_options); } if (name == "smart") { if (m_with_history) { throw argument_error{"The 'smart' strategy is not supported for history files."}; } return std::make_unique(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") ("clean", po::value>(), "Clean attribute (version, changeset, timestamp, uid, user)") ; 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); if (!setup_common(vm, desc)) { return false; } setup_progress(vm); setup_input_file(vm); init_output_file(vm); m_clean.setup(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(); const 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(); if (m_with_history) { m_output_file.set_has_multiple_object_versions(true); } m_extracts.push_back(std::make_unique(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(); if (m_with_history) { m_output_file.set_has_multiple_object_versions(true); } m_extracts.push_back(std::make_unique(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 << " attributes to clean: " << m_clean.to_string() << '\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 << '\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; } } if (m_extracts.empty()) { throw config_error{"No extract specified in config file or on the command line."}; } show_extracts(); m_strategy = make_strategy(m_strategy_name); m_strategy->show_arguments(m_vout); osmium::io::Header header; osmium::io::Header input_header; if (m_input_file.filename().empty()) { setup_header(header); } else { osmium::io::Reader reader{m_input_file, osmium::osm_entity_bits::nothing}; input_header = reader.header(); setup_header(header, input_header); reader.close(); } header.set("sorting", "Type_then_ID"); if (m_with_history) { header.set_has_multiple_object_versions(true); } for (const auto& extract : m_extracts) { osmium::io::Header file_header{header}; if (m_set_bounds) { file_header.add_box(extract->envelope()); } init_header(file_header, input_header, extract->header_options()); extract->open_file(file_header, m_output_overwrite, m_fsync, &m_clean); } 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.14.0/src/command_extract.hpp000066400000000000000000000050511420023413700205260ustar00rootroot00000000000000#ifndef COMMAND_EXTRACT_HPP #define COMMAND_EXTRACT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include "extract/extract.hpp" #include "extract/strategy.hpp" #include #include #include #include #include #include class CommandExtract : public CommandWithSingleOSMInput, public with_osm_output { static const std::size_t initial_buffer_size = 10 * 1024; std::vector> m_extracts; osmium::Options m_options; std::string m_config_file_name; std::string m_config_directory; std::string m_output_directory; std::string m_strategy_name; osmium::memory::Buffer m_buffer{initial_buffer_size, osmium::memory::Buffer::auto_grow::yes}; std::unique_ptr m_strategy; 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: explicit CommandExtract(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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.14.0/src/command_fileinfo.cpp000066400000000000000000000742601420023413700206520ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_fileinfo.hpp" #include "exception.hpp" #include "util.hpp" #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 #include #include #include #ifndef _MSC_VER # include #endif /*************************************************************************/ 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; uint64_t buffers_count = 0; uint64_t buffers_size = 0; uint64_t buffers_capacity = 0; osmium::min_op smallest_changeset_id{}; osmium::min_op smallest_node_id{}; osmium::min_op smallest_way_id{}; osmium::min_op smallest_relation_id{}; osmium::max_op largest_changeset_id{}; osmium::max_op largest_node_id{}; osmium::max_op largest_way_id{}; osmium::max_op largest_relation_id{}; osmium::metadata_options metadata_all_objects{"all"}; osmium::metadata_options metadata_some_objects{"none"}; osmium::min_op first_timestamp; osmium::max_op last_timestamp; osmium::CRC crc32; bool ordered = true; bool multiple_versions = false; bool calculate_crc = false; osmium::item_type last_type = osmium::item_type::undefined; osmium::object_id_type last_id = 0; explicit InfoHandler(bool with_crc) : calculate_crc(with_crc) { } 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(); if (calculate_crc) { crc32.update(changeset); } ++changesets; smallest_changeset_id.update(changeset.id()); largest_changeset_id.update(changeset.id()); } void osm_object(const osmium::OSMObject& object) { first_timestamp.update(object.timestamp()); last_timestamp.update(object.timestamp()); metadata_all_objects &= osmium::detect_available_metadata(object); metadata_some_objects |= osmium::detect_available_metadata(object); 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) { if (calculate_crc) { crc32.update(node); } bounds.extend(node.location()); ++nodes; smallest_node_id.update(node.id()); largest_node_id.update(node.id()); } void way(const osmium::Way& way) { if (calculate_crc) { crc32.update(way); } ++ways; smallest_way_id.update(way.id()); largest_way_id.update(way.id()); } void relation(const osmium::Relation& relation) { if (calculate_crc) { crc32.update(relation); } ++relations; smallest_relation_id.update(relation.id()); largest_relation_id.update(relation.id()); } }; // struct InfoHandler class Output { bool m_calculate_crc = false; public: Output() noexcept = default; virtual ~Output() noexcept = default; Output(const Output&) = delete; Output& operator=(const Output&) = delete; Output(Output&&) noexcept = delete; Output& operator=(Output&&) noexcept = delete; bool calculate_crc() const noexcept { return m_calculate_crc; } void set_crc(bool with_crc) noexcept { m_calculate_crc = with_crc; } 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 static osmium::object_id_type get_smallest(osmium::object_id_type id) noexcept { return id == osmium::min_op{}() ? 0 : id; } static osmium::object_id_type get_largest(osmium::object_id_type id) noexcept { return id == osmium::max_op{}() ? 0 : id; } class HumanReadableOutput : public Output { public: void file(const std::string& input_filename, const osmium::io::File& input_file) 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: " << file_size(input_file) << "\n"; } } void header(const osmium::io::Header& header) 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) 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"; } if (calculate_crc()) { std::cout << " CRC32: " << std::hex << info_handler.crc32().checksum() << std::dec << "\n"; } else { std::cout << " CRC32: not calculated (use --crc/-c to enable)\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 << " Smallest changeset ID: " << get_smallest(info_handler.smallest_changeset_id()) << "\n"; std::cout << " Smallest node ID: " << get_smallest(info_handler.smallest_node_id()) << "\n"; std::cout << " Smallest way ID: " << get_smallest(info_handler.smallest_way_id()) << "\n"; std::cout << " Smallest relation ID: " << get_smallest(info_handler.smallest_relation_id()) << "\n"; std::cout << " Largest changeset ID: " << get_largest(info_handler.largest_changeset_id()) << "\n"; std::cout << " Largest node ID: " << get_largest(info_handler.largest_node_id()) << "\n"; std::cout << " Largest way ID: " << get_largest(info_handler.largest_way_id()) << "\n"; std::cout << " Largest relation ID: " << get_largest(info_handler.largest_relation_id()) << "\n"; const auto num_objects = info_handler.changesets + info_handler.nodes + info_handler.ways + info_handler.relations; std::cout << " Number of buffers: " << info_handler.buffers_count; if (num_objects != 0) { std::cout << " (avg " << (num_objects / info_handler.buffers_count) << " objects per buffer)\n"; } else { std::cout << '\n'; } std::cout << " Sum of buffer sizes: " << info_handler.buffers_size << " (" << show_gbytes(info_handler.buffers_size) << " GB)\n"; if (info_handler.buffers_capacity != 0) { const auto fill_factor = std::round(100 * static_cast(info_handler.buffers_size) / static_cast(info_handler.buffers_capacity)); std::cout << " Sum of buffer capacities: " << info_handler.buffers_capacity << " (" << show_gbytes(info_handler.buffers_capacity) << " GB, " << fill_factor << "% full)\n"; } else { std::cout << " Sum of buffer capacities: 0 (0 GB)\n"; } std::cout << "Metadata:\n"; std::cout << " All objects have following metadata attributes: " << info_handler.metadata_all_objects << "\n"; std::cout << " Some objects have following metadata attributes: " << info_handler.metadata_some_objects << "\n"; } }; // class HumanReadableOutput class JSONOutput : public Output { using writer_type = rapidjson::PrettyWriter; rapidjson::StringBuffer m_stream; writer_type m_writer; public: JSONOutput() : m_writer(m_stream) { m_writer.StartObject(); } void file(const std::string& input_filename, const osmium::io::File& input_file) 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(file_size(input_file)); } 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) 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) 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); } if (calculate_crc()) { 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("minid"); m_writer.StartObject(); m_writer.String("changesets"); m_writer.Int64(get_smallest(info_handler.smallest_changeset_id())); m_writer.String("nodes"); m_writer.Int64(get_smallest(info_handler.smallest_node_id())); m_writer.String("ways"); m_writer.Int64(get_smallest(info_handler.smallest_way_id())); m_writer.String("relations"); m_writer.Int64(get_smallest(info_handler.smallest_relation_id())); m_writer.EndObject(); m_writer.String("maxid"); m_writer.StartObject(); m_writer.String("changesets"); m_writer.Int64(get_largest(info_handler.largest_changeset_id())); m_writer.String("nodes"); m_writer.Int64(get_largest(info_handler.largest_node_id())); m_writer.String("ways"); m_writer.Int64(get_largest(info_handler.largest_way_id())); m_writer.String("relations"); m_writer.Int64(get_largest(info_handler.largest_relation_id())); m_writer.EndObject(); m_writer.String("buffers"); m_writer.StartObject(); m_writer.String("count"); m_writer.Int64(get_largest(info_handler.buffers_count)); m_writer.String("size"); m_writer.Int64(get_largest(info_handler.buffers_size)); m_writer.String("capacity"); m_writer.Int64(get_largest(info_handler.buffers_capacity)); m_writer.EndObject(); m_writer.String("metadata"); m_writer.StartObject(); m_writer.String("all_objects"); m_writer.StartObject(); m_writer.String("version"); m_writer.Bool(info_handler.metadata_all_objects.version()); m_writer.String("timestamp"); m_writer.Bool(info_handler.metadata_all_objects.timestamp()); m_writer.String("changeset"); m_writer.Bool(info_handler.metadata_all_objects.changeset()); m_writer.String("user"); m_writer.Bool(info_handler.metadata_all_objects.user()); m_writer.String("uid"); m_writer.Bool(info_handler.metadata_all_objects.uid()); m_writer.EndObject(); m_writer.String("some_objects"); m_writer.StartObject(); m_writer.String("version"); m_writer.Bool(info_handler.metadata_some_objects.version()); m_writer.String("timestamp"); m_writer.Bool(info_handler.metadata_some_objects.timestamp()); m_writer.String("changeset"); m_writer.Bool(info_handler.metadata_some_objects.changeset()); m_writer.String("user"); m_writer.Bool(info_handler.metadata_some_objects.user()); m_writer.String("uid"); m_writer.Bool(info_handler.metadata_some_objects.uid()); m_writer.EndObject(); m_writer.EndObject(); m_writer.EndObject(); } void output() final { m_writer.EndObject(); std::cout << m_stream.GetString() << "\n"; } }; // class JSONOutput class SimpleOutput : public Output { std::string m_get_value; public: explicit SimpleOutput(std::string get_value) : m_get_value(std::move(get_value)) { } void file(const std::string& input_filename, const osmium::io::File& input_file) final { if (m_get_value == "file.name") { std::cout << input_filename << "\n"; return; } if (m_get_value == "file.format") { std::cout << input_file.format() << "\n"; return; } if (m_get_value == "file.compression") { std::cout << input_file.compression() << "\n"; return; } if (m_get_value == "file.size") { if (input_file.filename().empty()) { std::cout << 0 << "\n"; } else { std::cout << file_size(input_file) << "\n"; } return; } } void header(const osmium::io::Header& header) final { if (m_get_value == "header.boxes") { for (const auto& box : header.boxes()) { std::cout << box << "\n"; } } if (m_get_value == "header.with_history") { std::cout << yes_no(header.has_multiple_object_versions()); return; } 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) final { if (m_get_value == "data.bbox") { std::cout << info_handler.bounds << "\n"; return; } 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"; } return; } 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"; } return; } if (m_get_value == "data.objects_ordered") { std::cout << (info_handler.ordered ? "yes\n" : "no\n"); return; } 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"; } return; } if (m_get_value == "data.crc32") { std::cout << std::hex << info_handler.crc32().checksum() << std::dec << "\n"; return; } if (m_get_value == "data.count.changesets") { std::cout << info_handler.changesets << "\n"; return; } if (m_get_value == "data.count.nodes") { std::cout << info_handler.nodes << "\n"; return; } if (m_get_value == "data.count.ways") { std::cout << info_handler.ways << "\n"; return; } if (m_get_value == "data.count.relations") { std::cout << info_handler.relations << "\n"; return; } if (m_get_value == "data.minid.changesets") { std::cout << get_smallest(info_handler.smallest_changeset_id()) << "\n"; return; } if (m_get_value == "data.minid.nodes") { std::cout << get_smallest(info_handler.smallest_node_id()) << "\n"; return; } if (m_get_value == "data.minid.ways") { std::cout << get_smallest(info_handler.smallest_way_id()) << "\n"; return; } if (m_get_value == "data.minid.relations") { std::cout << get_smallest(info_handler.smallest_relation_id()) << "\n"; return; } if (m_get_value == "data.maxid.changesets") { std::cout << get_largest(info_handler.largest_changeset_id()) << "\n"; return; } if (m_get_value == "data.maxid.nodes") { std::cout << get_largest(info_handler.largest_node_id()) << "\n"; return; } if (m_get_value == "data.maxid.ways") { std::cout << get_largest(info_handler.largest_way_id()) << "\n"; return; } if (m_get_value == "data.maxid.relations") { std::cout << get_largest(info_handler.largest_relation_id()) << "\n"; return; } if (m_get_value == "data.buffers.count") { std::cout << info_handler.buffers_count << "\n"; return; } if (m_get_value == "data.buffers.size") { std::cout << info_handler.buffers_size << "\n"; return; } if (m_get_value == "data.buffers.capacity") { std::cout << info_handler.buffers_capacity << "\n"; return; } if (m_get_value == "metadata.all_objects.version") { std::cout << (info_handler.metadata_all_objects.version() ? "yes\n" : "no\n"); return; } if (m_get_value == "metadata.all_objects.timestamp") { std::cout << (info_handler.metadata_all_objects.timestamp() ? "yes\n" : "no\n"); return; } if (m_get_value == "metadata.all_objects.changeset") { std::cout << (info_handler.metadata_all_objects.changeset() ? "yes\n" : "no\n"); return; } if (m_get_value == "metadata.all_objects.uid") { std::cout << (info_handler.metadata_all_objects.uid() ? "yes\n" : "no\n"); return; } if (m_get_value == "metadata.all_objects.user") { std::cout << (info_handler.metadata_all_objects.user() ? "yes\n" : "no\n"); return; } if (m_get_value == "metadata.some_objects.version") { std::cout << (info_handler.metadata_some_objects.version() ? "yes\n" : "no\n"); return; } if (m_get_value == "metadata.some_objects.timestamp") { std::cout << (info_handler.metadata_some_objects.timestamp() ? "yes\n" : "no\n"); return; } if (m_get_value == "metadata.some_objects.changeset") { std::cout << (info_handler.metadata_some_objects.changeset() ? "yes\n" : "no\n"); return; } if (m_get_value == "metadata.some_objects.uid") { std::cout << (info_handler.metadata_some_objects.uid() ? "yes\n" : "no\n"); return; } if (m_get_value == "metadata.some_objects.user") { std::cout << (info_handler.metadata_some_objects.user() ? "yes\n" : "no\n"); return; } } }; // 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") ("crc,c", "Calculate CRC") ("no-crc", "Do not calculate CRC") ("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_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); if (!setup_common(vm, desc)) { return false; } setup_progress(vm); setup_object_type_nwrc(vm); if (vm.count("extended")) { m_extended = true; } if (vm.count("json")) { m_json_output = true; } if (vm.count("crc") && vm.count("no-crc")) { throw argument_error{"Can not use --crc/-c option and --no-crc at the same time."}; } if (m_extended && (vm.count("crc") || (m_json_output && !vm.count("no-crc")))) { m_calculate_crc = true; } const std::vector known_values = { "file.name", "file.format", "file.compression", "file.size", "header.boxes", "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.minid.nodes", "data.minid.ways", "data.minid.relations", "data.minid.changesets", "data.maxid.nodes", "data.maxid.ways", "data.maxid.relations", "data.maxid.changesets", "data.buffers.count", "data.buffers.size", "data.buffers.capacity", "metadata.all_objects.version", "metadata.all_objects.timestamp", "metadata.all_objects.changeset", "metadata.all_objects.uid", "metadata.all_objects.user", "metadata.some_objects.version", "metadata.some_objects.timestamp", "metadata.some_objects.changeset", "metadata.some_objects.uid", "metadata.some_objects.user" }; if (vm.count("show-variables")) { std::copy(known_values.cbegin(), known_values.cend(), std::ostream_iterator(std::cout, "\n")); return false; } 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."}; } m_calculate_crc = (m_get_value == "data.crc32"); } 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"; show_object_types(m_vout); m_vout << " extended output: " << (m_extended ? "yes\n" : "no\n"); m_vout << " calculate CRC: " << (m_calculate_crc ? "yes\n" : "no\n"); } bool CommandFileinfo::run() { std::unique_ptr output; if (m_json_output) { output = std::make_unique(); } else if (m_get_value.empty()) { output = std::make_unique(); } else { output = std::make_unique(m_get_value); } output->set_crc(m_calculate_crc); output->file(m_input_filename, m_input_file); osmium::io::Reader reader{m_input_file, m_extended ? osm_entity_bits() : osmium::osm_entity_bits::nothing}; osmium::io::Header header{reader.header()}; output->header(header); if (m_extended) { InfoHandler info_handler{m_calculate_crc}; osmium::ProgressBar progress_bar{reader.file_size(), display_progress()}; while (osmium::memory::Buffer buffer = reader.read()) { progress_bar.update(reader.offset()); ++info_handler.buffers_count; info_handler.buffers_size += buffer.committed(); info_handler.buffers_capacity += buffer.capacity(); 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.14.0/src/command_fileinfo.hpp000066400000000000000000000031661420023413700206540ustar00rootroot00000000000000#ifndef COMMAND_FILEINFO_HPP #define COMMAND_FILEINFO_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include class CommandFileinfo : public CommandWithSingleOSMInput { std::string m_get_value; bool m_extended = false; bool m_json_output = false; bool m_calculate_crc = false; public: explicit CommandFileinfo(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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.14.0/src/command_getid.cpp000066400000000000000000000337511420023413700201530ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_getid.hpp" #include "exception.hpp" #include "id_file.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include std::size_t CommandGetId::count_ids() const noexcept { 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") ("remove-tags,t", "Remove tags from objects not explicitly requested") ("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); if (!setup_common(vm, desc)) { return false; } setup_progress(vm); setup_input_file(vm); setup_output_file(vm); if (vm.count("add-referenced")) { if (m_input_filename.empty() || 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")) { m_default_item_type = parse_item_type(vm["default-type"].as()); } if (vm.count("remove-tags")) { m_remove_tags = true; if (!m_add_referenced_objects) { std::cerr << "Warning! Without -r/--add-referenced use of -t/--remove-tags isn't doing anything.\n"; } } 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.empty() || m_input_filename == "-") { throw argument_error{"Can not read OSM input and IDs both from STDIN."}; } m_vout << "Reading IDs from STDIN...\n"; read_id_file(std::cin, m_ids, m_default_item_type); } else { std::ifstream id_file{filename}; if (!id_file.is_open()) { throw argument_error{"Could not open file '" + filename + "'"}; } m_vout << "Reading ID file...\n"; read_id_file(id_file, m_ids, m_default_item_type); } } } if (vm.count("id-osm-file")) { for (const std::string& filename : vm["id-osm-file"].as>()) { m_vout << "Reading OSM ID file...\n"; read_id_osm_file(filename, m_ids); } } 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, m_ids, m_default_item_type); } } if (no_ids(m_ids)) { throw argument_error{"Please specify IDs to look for on command line or with option --id-file/-i or --id-osm-file/-I."}; } m_matching_ids = m_ids; 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); if (m_add_referenced_objects) { m_vout << " remove tags on non-matching objects: " << yes_no(m_remove_tags); } 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; } 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::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, osmium::io::read_meta::no}; 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, osmium::io::read_meta::no}; 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, osmium::io::read_meta::no}; 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, m_ids); } } } 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 (auto& object : buffer.select()) { if (m_matching_ids(object.type()).get(object.positive_id())) { if (!m_work_with_history) { m_ids(object.type()).unset(object.positive_id()); } writer(object); } else if (m_ids(object.type()).get(object.positive_id())) { if (!m_work_with_history) { m_ids(object.type()).unset(object.positive_id()); } if (m_remove_tags) { object.remove_tags(); } 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_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(m_ids); } osmium-tool-1.14.0/src/command_getid.hpp000066400000000000000000000052561420023413700201570ustar00rootroot00000000000000#ifndef COMMAND_GETID_HPP #define COMMAND_GETID_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include #include #include #include #include #include #include #include #include #include class CommandGetId : public CommandWithSingleOSMInput, public with_osm_output { osmium::nwr_array> m_matching_ids; osmium::nwr_array> m_ids; 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_remove_tags = false; bool m_verbose_ids = false; osmium::osm_entity_bits::type get_needed_types() const; std::size_t count_ids() const noexcept; void find_referenced_objects(); 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: explicit CommandGetId(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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.14.0/src/command_getparents.cpp000066400000000000000000000203131420023413700212210ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_getparents.hpp" #include "exception.hpp" #include "id_file.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bool CommandGetParents::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") ("add-self,s", "Add objects with specified IDs themselves") ("verbose-ids", "Print all requested 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); if (!setup_common(vm, desc)) { return false; } setup_progress(vm); setup_input_file(vm); setup_output_file(vm); if (vm.count("add-self")) { m_add_self = true; } if (vm.count("default-type")) { m_default_item_type = parse_item_type(vm["default-type"].as()); } 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.empty() || m_input_filename == "-") { throw argument_error{"Can not read OSM input and IDs both from STDIN."}; } m_vout << "Reading IDs from STDIN...\n"; read_id_file(std::cin, m_ids, m_default_item_type); } else { std::ifstream id_file{filename}; if (!id_file.is_open()) { throw argument_error{"Could not open file '" + filename + "'"}; } m_vout << "Reading ID file...\n"; read_id_file(id_file, m_ids, m_default_item_type); } } } if (vm.count("id-osm-file")) { for (const std::string& filename : vm["id-osm-file"].as>()) { m_vout << "Reading OSM ID file...\n"; read_id_osm_file(filename, m_ids); } } 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, m_ids, m_default_item_type); } } if (no_ids(m_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 CommandGetParents::show_arguments() { show_single_input_arguments(m_vout); show_output_arguments(m_vout); m_vout << " other options:\n"; m_vout << " add self: " << yes_no(m_add_self); 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 CommandGetParents::get_needed_types() const { osmium::osm_entity_bits::type types = osmium::osm_entity_bits::relation; if (!m_ids(osmium::item_type::node).empty()) { if (m_add_self) { types |= osmium::osm_entity_bits::node; } types |= osmium::osm_entity_bits::way; } if (!m_ids(osmium::item_type::way).empty()) { if (m_add_self) { types |= osmium::osm_entity_bits::way; } } return types; } bool CommandGetParents::run() { 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_add_self && m_ids(object.type()).get(object.positive_id())) { writer(object); continue; } if (object.type() == osmium::item_type::way) { const auto& way = static_cast(object); for (const auto& nr : way.nodes()) { if (m_ids(osmium::item_type::node).get(nr.positive_ref())) { writer(object); break; } } } else if (object.type() == osmium::item_type::relation) { const auto& relation = static_cast(object); for (const auto& member : relation.members()) { if (m_ids(member.type()).get(member.positive_ref())) { writer(object); break; } } } } } 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.14.0/src/command_getparents.hpp000066400000000000000000000045341420023413700212350ustar00rootroot00000000000000#ifndef COMMAND_GETPARENTS_HPP #define COMMAND_GETPARENTS_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include #include #include #include #include #include #include #include #include #include class CommandGetParents : public CommandWithSingleOSMInput, public with_osm_output { osmium::nwr_array> m_ids; osmium::item_type m_default_item_type = osmium::item_type::node; bool m_add_self = false; bool m_verbose_ids = false; osmium::osm_entity_bits::type get_needed_types() const; void add_nodes(const osmium::Way& way); void add_members(const osmium::Relation& relation); public: explicit CommandGetParents(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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 "getparents"; } const char* synopsis() const noexcept override final { return "osmium getparents [OPTIONS] OSM-FILE ID...\n" " osmium getparents [OPTIONS] OSM-FILE -i ID-FILE\n" " osmium getparents [OPTIONS] OSM-FILE -I ID-OSM-FILE"; } }; // class CommandGetParents #endif // COMMAND_GETPARENTS_HPP osmium-tool-1.14.0/src/command_help.cpp000066400000000000000000000065771420023413700200150ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_help.hpp" #include #include #include #include #ifndef _MSC_VER # include #endif 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 https://osmcode.org/osmium-tool/\n"; } bool CommandHelp::run() { const auto commands = m_command_factory.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(m_command_factory.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" " output-headers Header options that can be set on output files\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; } const auto description = m_command_factory.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; } if (m_topic == "output-headers") { show_help("output-headers", ""); return true; } std::cerr << "Unknown help topic '" << m_topic << "'.\n"; return false; } osmium-tool-1.14.0/src/command_help.hpp000066400000000000000000000027101420023413700200030ustar00rootroot00000000000000#ifndef COMMAND_HELP_HPP #define COMMAND_HELP_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include class CommandHelp : public Command { std::string m_topic; public: explicit CommandHelp(const CommandFactory& command_factory) : Command(command_factory) { } 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.14.0/src/command_merge.cpp000066400000000000000000000211571420023413700201530ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_merge.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bool CommandMerge::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("with-history,H", "Do not warn about input files with multiple object versions") ; 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 (!setup_common(vm, desc)) { return false; } setup_progress(vm); setup_input_files(vm); setup_output_file(vm); if (vm.count("with-history")) { m_with_history = true; } 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 m_reader; std::string m_name; it_type m_iterator; osmium::item_type m_last_type = osmium::item_type::node; osmium::object_id_type m_last_id = 0; osmium::object_version_type m_last_version = 0; bool m_warning; public: explicit DataSource(const osmium::io::File& file, bool with_history) : m_reader(std::make_unique(file)), m_name(file.filename()), m_iterator(*m_reader), m_warning(!with_history) { if (m_iterator != it_type{}) { m_last_type = m_iterator->type(); m_last_id = m_iterator->id(); m_last_version = m_iterator->version(); } } bool empty() const noexcept { return m_iterator == it_type{}; } bool next() { ++m_iterator; if (m_iterator == it_type{}) { // reached end of file return false; } if (m_iterator->type() < m_last_type) { throw std::runtime_error{"Objects in input file '" + m_name + "' out of order (must be nodes, then ways, then relations)."}; } if (m_iterator->type() > m_last_type) { m_last_type = m_iterator->type(); m_last_id = m_iterator->id(); m_last_version = m_iterator->version(); return true; } if (m_iterator->id() < m_last_id) { throw std::runtime_error{"Objects in input file '" + m_name + "' out of order (smaller ids must come first)."}; } if (m_iterator->id() > m_last_id) { m_last_id = m_iterator->id(); m_last_version = m_iterator->version(); return true; } if (m_iterator->version() < m_last_version) { throw std::runtime_error{"Objects in input file '" + m_name + "' out of order (smaller version must come first)."}; } if (m_iterator->version() == m_last_version) { throw std::runtime_error{"Two objects in input file '" + m_name + "' with same version."}; } if (m_warning) { std::cerr << "Warning: Multiple objects with same id in input file '" + m_name + "'!\n"; std::cerr << "If you are reading history files, this is to be expected. Use --with-history to disable warning.\n"; m_warning = false; } m_last_version = m_iterator->version(); return true; } const osmium::OSMObject* get() noexcept { return &*m_iterator; } std::size_t offset() const noexcept { return m_reader->offset(); } }; // 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::ReaderWithProgressBar reader{display_progress(), m_input_files[0]}; while (osmium::memory::Buffer buffer = reader.read()) { writer(std::move(buffer)); } } else { m_vout << "Merging " << m_input_files.size() << " input files to output file...\n"; osmium::ProgressBar progress_bar{file_size_sum(m_input_files), display_progress()}; 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, m_with_history); if (!data_sources.back().empty()) { queue.emplace(data_sources.back().get(), index); } ++index; } int n = 0; while (!queue.empty()) { const 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); } if (n++ > 10000) { n = 0; progress_bar.update(std::accumulate(data_sources.cbegin(), data_sources.cend(), static_cast(0), [](std::size_t sum, const DataSource& source){ return sum + source.offset(); })); } } } m_vout << "Closing output file...\n"; writer.close(); show_memory_used(); m_vout << "Done.\n"; return true; } osmium-tool-1.14.0/src/command_merge.hpp000066400000000000000000000030441420023413700201530ustar00rootroot00000000000000#ifndef COMMAND_MERGE_HPP #define COMMAND_MERGE_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include class CommandMerge : public CommandWithMultipleOSMInputs, public with_osm_output { bool m_with_history = false; public: explicit CommandMerge(const CommandFactory& command_factory) : CommandWithMultipleOSMInputs(command_factory) { } 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.14.0/src/command_merge_changes.cpp000066400000000000000000000125501420023413700216400ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_merge_changes.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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); if (!setup_common(vm, desc)) { return false; } setup_progress(vm); 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"; osmium::ProgressBar progress_bar{file_size_sum(m_input_files), display_progress()}; 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()) { progress_bar.update(reader.offset()); osmium::apply(buffer, objects); changes.push_back(std::move(buffer)); } progress_bar.file_done(reader.file_size()); reader.close(); } progress_bar.done(); // 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"; // This is needed for a special case: When change files have been // created from extracts it is possible that they contain objects // with the same type, id, version, and timestamp. In that case we // still want to get the last object available. So we have to make // sure it appears first in the objects vector before doing the // stable sort. std::reverse(objects.ptr_begin(), objects.ptr_end()); 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.14.0/src/command_merge_changes.hpp000066400000000000000000000031531420023413700216440ustar00rootroot00000000000000#ifndef COMMAND_MERGE_CHANGES_HPP #define COMMAND_MERGE_CHANGES_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include class CommandMergeChanges : public CommandWithMultipleOSMInputs, public with_osm_output { bool m_simplify_change = false; public: explicit CommandMergeChanges(const CommandFactory& command_factory) : CommandWithMultipleOSMInputs(command_factory) { } 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.14.0/src/command_query_locations_index.cpp000066400000000000000000000124561420023413700234650ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_query_locations_index.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include bool CommandQueryLocationsIndex::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("index-file,i", po::value(), "Index file name (required)") ("dump", "Dump all locations to STDOUT") ; po::options_description opts_common{add_common_options(false)}; po::options_description opts_output{add_output_options()}; po::options_description hidden; hidden.add_options() ("node-id", po::value(), "Node ID") ; po::options_description desc; desc.add(opts_cmd).add(opts_common).add(opts_output); po::options_description parsed_options; parsed_options.add(desc).add(hidden); po::positional_options_description positional; positional.add("node-id", 1); po::variables_map vm; po::store(po::command_line_parser(arguments).options(parsed_options).positional(positional).run(), vm); po::notify(vm); if (!setup_common(vm, desc)) { return false; } init_output_file(vm); if (vm.count("index-file")) { m_index_file_name = vm["index-file"].as(); } else { throw argument_error{"Missing --index-file,-i option."}; } if (vm.count("dump")) { m_dump = true; if ((m_output_filename.empty() || m_output_filename == "-") && m_output_format.empty()) { m_output_format = "opl,add_metadata=none"; } if (m_output_format.empty()) { m_output_file = osmium::io::File{m_output_filename}; m_output_file.set("add_metadata", "none"); } else { m_output_file = osmium::io::File{m_output_filename, m_output_format}; } m_output_file.check(); } if (vm.count("node-id")) { if (m_dump) { throw argument_error{"Either use --dump or use node ID, not both."}; } const auto id = vm["node-id"].as(); const auto r = osmium::string_to_object_id(id.c_str(), osmium::osm_entity_bits::node, osmium::item_type::node); m_id = static_cast(r.second); } else if (!m_dump) { throw argument_error{"Missing node ID on command line."}; } return true; } void CommandQueryLocationsIndex::show_arguments() { show_output_arguments(m_vout); m_vout << " other options:\n"; m_vout << " index file: " << m_index_file_name << '\n'; } bool CommandQueryLocationsIndex::run() { const int fd = ::open(m_index_file_name.c_str(), O_RDWR); if (fd == -1) { throw std::system_error{errno, std::system_category(), std::string("Can not open index file '") + m_index_file_name + "'"}; } osmium::index::map::DenseFileArray location_index{fd}; if (m_dump) { const std::size_t max_buffer_size = 11UL * 1024UL * 1024UL; osmium::memory::Buffer buffer{max_buffer_size}; 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}; m_vout << "Dumping index as OSM file...\n"; for (std::size_t i = 0; i < location_index.size(); ++i) { if (location_index.get_noexcept(i).valid()) { osmium::builder::NodeBuilder builder{buffer}; builder.set_id(static_cast(i)); builder.set_location(location_index.get_noexcept(i)); } buffer.commit(); if (buffer.committed() > 10UL * 1024UL * 1024UL) { writer(std::move(buffer)); buffer = osmium::memory::Buffer{max_buffer_size}; } } if (buffer.committed() > 0) { writer(std::move(buffer)); } } else { m_vout << "Looking up location in index...\n"; const auto location = location_index.get(m_id); std::cout << location << '\n'; } m_vout << "Done.\n"; return true; } osmium-tool-1.14.0/src/command_query_locations_index.hpp000066400000000000000000000033371420023413700234700ustar00rootroot00000000000000#ifndef COMMAND_QUERY_LOCATIONS_INDEX_HPP #define COMMAND_QUERY_LOCATIONS_INDEX_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include #include class CommandQueryLocationsIndex : public Command, public with_osm_output { std::string m_index_file_name; osmium::object_id_type m_id = 0; bool m_dump = false; public: explicit CommandQueryLocationsIndex(const CommandFactory& command_factory) : Command(command_factory) { } 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 "query-locations-index"; } const char* synopsis() const noexcept override final { return "osmium query-locations-index -i INDEX-FILE [OPTIONS] NODE-ID"; } }; // class CommandQueryLocationsIndex #endif // COMMAND_QUERY_LOCATIONS_INDEX_HPP osmium-tool-1.14.0/src/command_removeid.cpp000066400000000000000000000136601420023413700206660ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_removeid.hpp" #include "exception.hpp" #include "id_file.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bool CommandRemoveId::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") ; 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); if (!setup_common(vm, desc)) { return false; } setup_progress(vm); setup_input_file(vm); setup_output_file(vm); if (vm.count("default-type")) { m_default_item_type = parse_item_type(vm["default-type"].as()); } if (vm.count("id-file")) { for (const std::string& filename : vm["id-file"].as>()) { if (filename == "-") { if (m_input_filename.empty() || m_input_filename == "-") { throw argument_error{"Can not read OSM input and IDs both from STDIN."}; } m_vout << "Reading IDs from STDIN...\n"; read_id_file(std::cin, m_ids, m_default_item_type); } else { std::ifstream id_file{filename}; if (!id_file.is_open()) { throw argument_error{"Could not open file '" + filename + "'"}; } m_vout << "Reading ID file...\n"; read_id_file(id_file, m_ids, m_default_item_type); } } } if (vm.count("id-osm-file")) { for (const std::string& filename : vm["id-osm-file"].as>()) { m_vout << "Reading OSM ID file...\n"; read_id_osm_file(filename, m_ids); } } 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, m_ids, m_default_item_type); } } if (no_ids(m_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 CommandRemoveId::show_arguments() { show_single_input_arguments(m_vout); show_output_arguments(m_vout); m_vout << " other options:\n"; m_vout << " default object type: " << osmium::item_type_to_name(m_default_item_type) << "\n"; m_vout << " removing " << 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"; } bool CommandRemoveId::run() { m_vout << "Opening input file...\n"; osmium::io::Reader reader{m_input_file, osmium::osm_entity_bits::nwr}; 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 non-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 (auto& object : buffer.select()) { if (!m_ids(object.type()).get(object.positive_id())) { 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.14.0/src/command_removeid.hpp000066400000000000000000000041501420023413700206650ustar00rootroot00000000000000#ifndef COMMAND_REMOVEID_HPP #define COMMAND_REMOVEID_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include #include #include #include #include #include #include #include #include #include class CommandRemoveId : public CommandWithSingleOSMInput, public with_osm_output { osmium::nwr_array> m_ids; osmium::item_type m_default_item_type = osmium::item_type::node; public: explicit CommandRemoveId(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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 "removeid"; } const char* synopsis() const noexcept override final { return "osmium removeid [OPTIONS] OSM-FILE ID...\n" " osmium removeid [OPTIONS] OSM-FILE -i ID-FILE\n" " osmium removeid [OPTIONS] OSM-FILE -I ID-OSM-FILE"; } }; // class CommandRemoveId #endif // COMMAND_REMOVEID_HPP osmium-tool-1.14.0/src/command_renumber.cpp000066400000000000000000000353461420023413700207000ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_renumber.hpp" #include "exception.hpp" #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 #include #include #ifdef _WIN32 # include #endif osmium::object_id_type id_map::add_offset_to_id(osmium::object_id_type id) const noexcept { if (m_start_id < 0) { return -id + m_start_id + 1; } return id + m_start_id - 1; } 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 add_offset_to_id(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 add_offset_to_id(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 add_offset_to_id(m_ids.size()); } // Old ID found in m_ids, return. return add_offset_to_id(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()), // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) sizeof(osmium::object_id_type) * m_ids.size() ); } void id_map::print(osmium::object_id_type new_id) { for (const auto& m : m_extra_ids) { m_ids[m.second - 1] = m.first; } for (const auto& id : m_ids) { std::cout << id << ' ' << new_id << '\n'; if (new_id > 0) { ++new_id; } else { --new_id; } } } 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::TypedMemoryMapping mapping{num_elements, osmium::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(); } } } static osmium::object_id_type get_start_id(const std::string& s) { const auto id = osmium::string_to_object_id(s.c_str()); if (id == 0) { return 1; } return id; } void CommandRenumber::set_start_ids(const std::string& str) { const auto start_ids = osmium::split_string(str, ','); if (start_ids.size() == 1) { const auto id = get_start_id(start_ids[0]); m_id_map(osmium::item_type::node).set_start_id(id); m_id_map(osmium::item_type::way).set_start_id(id); m_id_map(osmium::item_type::relation).set_start_id(id); } else if (start_ids.size() == 3) { m_id_map(osmium::item_type::node).set_start_id(get_start_id(start_ids[0])); m_id_map(osmium::item_type::way).set_start_id(get_start_id(start_ids[1])); m_id_map(osmium::item_type::relation).set_start_id(get_start_id(start_ids[2])); } else { throw argument_error{"The --start-id/s option must be followed by exactly 1 ID or 3 IDs separated by commas"}; } } void CommandRenumber::show_index(const std::string& type) { auto t = osmium::item_type::undefined; if (type == "n" || type == "node") { t = osmium::item_type::node; } else if (type == "w" || type == "way") { t = osmium::item_type::way; } else if (type == "r" || type == "relation") { t = osmium::item_type::relation; } else { throw argument_error{"Invalid value for --show-index option. Allowed are 'node', 'way', or 'relation'"}; } read_start_ids_file(); read_index(t); m_id_map(t).print(m_id_map(t).start_id()); } 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)") ("show-index", po::value(), "Show contents of index file") ("start-id,s", po::value(), "Comma separated list of first node, way, and relation id to use (default: 1,1,1)") ; 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); if (vm.count("index-directory")) { m_index_directory = vm["index-directory"].as(); } if (vm.count("show-index")) { show_index(vm["show-index"].as()); return false; } if (!setup_common(vm, desc)) { return false; } setup_progress(vm); setup_object_type_nwr(vm); setup_input_file(vm); setup_output_file(vm); if (vm.count("start-id")) { set_start_ids(vm["start-id"].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 and their start IDs:"; if (osm_entity_bits() & osmium::osm_entity_bits::node) { m_vout << " node (" << m_id_map(osmium::item_type::node).start_id() << ')'; } if (osm_entity_bits() & osmium::osm_entity_bits::way) { m_vout << " way (" << m_id_map(osmium::item_type::way).start_id() << ')'; } if (osm_entity_bits() & osmium::osm_entity_bits::relation) { m_vout << " relation (" << m_id_map(osmium::item_type::relation).start_id() << ')'; } 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::system_error{errno, std::system_category(), "Could not open file '" + f + "'"}; } #ifdef _WIN32 _setmode(fd, _O_BINARY); #endif const std::size_t file_size = osmium::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); // NOLINT(hicpp-signed-bitwise) if (fd < 0) { throw std::system_error{errno, std::system_category(), "Could not open file '" + f + "'"}; } #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{input_file, osmium::osm_entity_bits::relation}; const auto input = osmium::io::make_input_iterator_range(reader); for (const osmium::Relation& relation : input) { (*map)(relation.id()); } reader.close(); } void CommandRenumber::read_start_ids_file() { std::ifstream start_id_file{m_index_directory + "/start_ids"}; if (start_id_file.is_open()) { std::string line; start_id_file >> line; start_id_file.close(); set_start_ids(line); } } bool CommandRenumber::run() { if (!m_index_directory.empty()) { m_vout << "Reading index files...\n"; read_start_ids_file(); 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 (of two) through input file (reading relations)...\n"; read_relations(m_input_file, &m_id_map(osmium::item_type::relation)); m_vout << "First pass done.\n"; m_vout << "Second pass (of two) through input file...\n"; } else { m_vout << "Single pass through input file (because relation IDs are not mapped)...\n"; } osmium::io::Reader reader{m_input_file}; osmium::io::Header header = reader.header(); setup_header(header); header.set("xml_josm_upload", "false"); header.set("sorting", "Type_then_ID"); 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()); renumber(buffer); writer(std::move(buffer)); } progress_bar.done(); reader.close(); m_vout << "Pass done.\n"; m_vout << "Closing output file...\n"; writer.close(); if (!m_index_directory.empty()) { m_vout << "Writing index files...\n"; std::ofstream start_id_file{m_index_directory + "/start_ids"}; start_id_file << m_id_map(osmium::item_type::node).start_id() << ',' << m_id_map(osmium::item_type::way).start_id() << ',' << m_id_map(osmium::item_type::relation).start_id() << '\n'; start_id_file.close(); 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.14.0/src/command_renumber.hpp000066400000000000000000000110361420023413700206730ustar00rootroot00000000000000#ifndef COMMAND_RENUMBER_HPP #define COMMAND_RENUMBER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include #include #include #include #include #include #include #include /** * 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. osmium::object_id_type m_start_id = 1; public: id_map() = default; osmium::object_id_type start_id() const noexcept { return m_start_id; } void set_start_id(osmium::object_id_type start_id) noexcept { m_start_id = start_id; } osmium::object_id_type add_offset_to_id(osmium::object_id_type id) const noexcept; // 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); void print(osmium::object_id_type new_id); // 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 CommandWithSingleOSMInput, 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 set_start_ids(const std::string& str); void read_start_ids_file(); void read_index(osmium::item_type type); void write_index(osmium::item_type type); void show_index(const std::string& type); public: explicit CommandRenumber(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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.14.0/src/command_show.cpp000066400000000000000000000163651420023413700200410ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_show.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef _MSC_VER # include #endif #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); if (!setup_common(vm, desc)) { return false; } 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.empty() ? "(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 throw std::system_error{errno, std::system_category(), "Could not run pager: dup2() call failed"}; } if (with_color && pager.size() >= 4 && 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. throw std::system_error{errno, std::system_category(), "Could not run pager: execlp() call failed"}; } // parent ::close(pipefd[0]); // close read end of the pipe 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); 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"}; } ::close(fd); 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; } } writer.close(); ::close(1); // close stdout to signal EOF to pager 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) { // NOLINT(hicpp-signed-bitwise) throw argument_error{std::string{"Could not run pager '"} + m_pager + "'"}; } #endif } reader.close(); return true; } osmium-tool-1.14.0/src/command_show.hpp000066400000000000000000000031641420023413700200370ustar00rootroot00000000000000#ifndef COMMAND_SHOW_HPP #define COMMAND_SHOW_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include class CommandShow : public CommandWithSingleOSMInput { std::string m_output_format{"debug,color=true"}; std::string m_pager; bool m_color_output = false; void setup_pager_from_env() noexcept; public: explicit CommandShow(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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.14.0/src/command_sort.cpp000066400000000000000000000205271420023413700200430ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_sort.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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") ("strategy,s", po::value(), "Strategy (default: simple)") ; 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); if (!setup_common(vm, desc)) { return false; } setup_progress(vm); setup_input_files(vm); setup_output_file(vm); if (vm.count("input-filenames")) { m_filenames = vm["input-filenames"].as>(); } if (vm.count("strategy")) { m_strategy = vm["strategy"].as(); if (m_strategy != "simple" && m_strategy != "multipass") { throw argument_error{"Unknown strategy: " + m_strategy}; } } return true; } void CommandSort::show_arguments() { show_multiple_inputs_arguments(m_vout); show_output_arguments(m_vout); m_vout << " other options:\n"; m_vout << " strategy: " << m_strategy << "\n"; } bool CommandSort::run_single_pass() { std::vector data; osmium::ObjectPointerCollection objects; osmium::Box bounding_box; uint64_t buffers_count = 0; uint64_t buffers_size = 0; uint64_t buffers_capacity = 0; m_vout << "Reading contents of input files...\n"; osmium::ProgressBar progress_bar{file_size_sum(m_input_files), display_progress()}; 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()) { ++buffers_count; buffers_size += buffer.committed(); buffers_capacity += buffer.capacity(); progress_bar.update(reader.offset()); osmium::apply(buffer, objects); data.push_back(std::move(buffer)); } progress_bar.file_done(reader.file_size()); reader.close(); } progress_bar.done(); m_vout << "Number of buffers: " << buffers_count << "\n"; m_vout << "Sum of buffer sizes: " << buffers_size << " (" << show_gbytes(buffers_size) << " GB)\n"; if (buffers_capacity != 0) { const auto fill_factor = std::round(100 * static_cast(buffers_size) / static_cast(buffers_capacity)); m_vout << "Sum of buffer capacities: " << buffers_capacity << " (" << show_gbytes(buffers_capacity) << " GB, " << fill_factor << "% full)\n"; } else { m_vout << "Sum of buffer capacities: 0 (0 GB)\n"; } m_vout << "Opening output file...\n"; osmium::io::Header header; setup_header(header); header.set("sorting", "Type_then_ID"); 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; } bool CommandSort::run_multi_pass() { osmium::Box bounding_box; m_vout << "Reading input file headers...\n"; for (const std::string& file_name : m_filenames) { osmium::io::Reader reader{file_name, osmium::osm_entity_bits::nothing}; osmium::io::Header header{reader.header()}; bounding_box.extend(header.joined_boxes()); 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}; osmium::ProgressBar progress_bar{file_size_sum(m_input_files) * 3, display_progress()}; int pass = 1; for (const auto entity : {osmium::osm_entity_bits::node, osmium::osm_entity_bits::way, osmium::osm_entity_bits::relation}) { std::vector data; osmium::ObjectPointerCollection objects; uint64_t buffers_count = 0; uint64_t buffers_size = 0; uint64_t buffers_capacity = 0; m_vout << "Pass " << pass++ << "...\n"; m_vout << "Reading contents of input files...\n"; for (const std::string& file_name : m_filenames) { osmium::io::Reader reader{file_name, entity}; osmium::io::Header header{reader.header()}; bounding_box.extend(header.joined_boxes()); while (osmium::memory::Buffer buffer = reader.read()) { ++buffers_count; buffers_size += buffer.committed(); buffers_capacity += buffer.capacity(); progress_bar.update(reader.offset()); osmium::apply(buffer, objects); data.push_back(std::move(buffer)); } progress_bar.file_done(reader.file_size()); reader.close(); } if (m_vout.verbose()) { progress_bar.remove(); } m_vout << "Number of buffers: " << buffers_count << "\n"; m_vout << "Sum of buffer sizes: " << buffers_size << " (" << show_gbytes(buffers_size) << " GB)\n"; if (buffers_capacity != 0) { const auto fill_factor = std::round(100 * static_cast(buffers_size) / static_cast(buffers_capacity)); m_vout << "Sum of buffer capacities: " << buffers_capacity << " (" << show_gbytes(buffers_capacity) << " GB, " << fill_factor << "% full)\n"; } else { m_vout << "Sum of buffer capacities: 0 (0 GB)\n"; } 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); } progress_bar.done(); m_vout << "Closing output file...\n"; writer.close(); show_memory_used(); m_vout << "Done.\n"; return true; } bool CommandSort::run() { if (m_strategy == "simple") { return run_single_pass(); } return run_multi_pass(); } osmium-tool-1.14.0/src/command_sort.hpp000066400000000000000000000032041420023413700200410ustar00rootroot00000000000000#ifndef COMMAND_SORT_HPP #define COMMAND_SORT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include class CommandSort : public CommandWithMultipleOSMInputs, public with_osm_output { std::vector m_filenames; std::string m_strategy{"simple"}; public: explicit CommandSort(const CommandFactory& command_factory) : CommandWithMultipleOSMInputs(command_factory) { } bool setup(const std::vector& arguments) override final; void show_arguments() override final; bool run_single_pass(); bool run_multi_pass(); 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.14.0/src/command_tags_count.cpp000066400000000000000000000220611420023413700212150ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_tags_count.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include void CommandTagsCount::add_matcher(const std::string& expression) { bool has_value_matcher = false; auto matcher = get_tag_matcher(expression, &has_value_matcher); if (has_value_matcher) { m_tags_filter.add_rule(true, std::move(matcher)); } else { m_keys_filter.add_rule(true, std::move(matcher)); } } void CommandTagsCount::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); } add_matcher(line); } } } static sort_func_type get_sort_function(const std::string& sort_order) { static const std::pair sort_options[] = { { "count-desc", [](const element_type& a, const element_type& b){ if (a.count == b.count) { return *a.name < *b.name; } return a.count > b.count; } }, { "count-asc", [](const element_type& a, const element_type& b){ if (a.count == b.count) { return *a.name < *b.name; } return a.count < b.count; } }, { "name-desc", [](const element_type& a, const element_type& b){ return *a.name > *b.name; } }, { "name-asc", [](const element_type& a, const element_type& b){ return *a.name < *b.name; } } }; for (const auto& nf : sort_options) { if (nf.first == sort_order) { return nf.second; } } throw argument_error{"Unknown sort order '" + sort_order + "'"}; } bool CommandTagsCount::setup(const std::vector& arguments) { po::options_description opts_cmd{"COMMAND OPTIONS"}; opts_cmd.add_options() ("expressions,e", po::value(), "Read tag expressions from file") ("min-count,m", po::value(), "Min count shown (default: 0)") ("max-count,M", po::value(), "Max count shown (default: none)") ("output,o", po::value(), "Output file (default: stdout)") ("overwrite,O", "Allow existing output file to be overwritten") ("sort,s", po::value(), "Sort order of results ('count-asc', 'count-desc' (default), 'name-asc', or 'name-desc')") ("object-type,t", po::value>(), "Read 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 hidden; hidden.add_options() ("input-filename", po::value(), "OSM input file") ("expression-list", po::value>(), "Count expressions") ; 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); 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); if (!setup_common(vm, desc)) { return false; } setup_progress(vm); setup_object_type_nwr(vm); setup_input_file(vm); if (vm.count("output")) { m_output_filename = vm["output"].as(); } if (vm.count("overwrite")) { m_output_overwrite = osmium::io::overwrite::allow; } if (vm.count("expression-list")) { for (const auto& e : vm["expression-list"].as>()) { add_matcher(e); } } else { m_keys_filter = osmium::TagsFilter{true}; } if (vm.count("expressions")) { read_expressions_file(vm["expressions"].as()); } if (vm.count("min-count")) { m_min_count = vm["min-count"].as(); } if (vm.count("max-count")) { m_max_count = vm["max-count"].as(); } if (vm.count("sort")) { m_sort_order = vm["sort"].as(); if (m_sort_order == "name") { m_sort_order = "name-asc"; } else if (m_sort_order == "count") { m_sort_order = "count-desc"; } } m_sort_func = get_sort_function(m_sort_order); return true; } void CommandTagsCount::show_arguments() { show_single_input_arguments(m_vout); m_vout << " output options:\n"; m_vout << " file name: " << m_output_filename << '\n'; m_vout << " overwrite: " << yes_no(m_output_overwrite == osmium::io::overwrite::allow); m_vout << " other options:\n"; m_vout << " sort order: " << m_sort_order << '\n'; m_vout << " min count: " << m_min_count << '\n'; if (m_max_count == std::numeric_limits::max()) { m_vout << " max count: (none)\n"; } else { m_vout << " max count: " << m_max_count << '\n'; } } std::vector CommandTagsCount::sort_results() const { std::vector results; results.reserve(m_counts.size()); for (const auto& c : m_counts) { if (c.second >= m_min_count && c.second <= m_max_count) { results.emplace_back(c.first, c.second); } } std::sort(results.begin(), results.end(), m_sort_func); return results; } static void append_escaped(std::string* out, const char* str) { *out += '"'; for (; *str != '\0'; ++str) { if (*str == '"') { *out += '"'; } *out += *str; } *out += '"'; } static void write_results(const std::vector& results, int fd) { std::string out; const std::size_t buffer_size = 1024UL * 1024UL; out.reserve(buffer_size); for (const auto& c : results) { out += std::to_string(c.count); out += '\t'; append_escaped(&out, c.name->key()); const char* value = c.name->value(); if (value) { out += '\t'; append_escaped(&out, value); } out += '\n'; if (out.size() > (buffer_size - 1000)) { osmium::io::detail::reliable_write(fd, out.data(), out.size()); out.clear(); } } osmium::io::detail::reliable_write(fd, out.data(), out.size()); close(fd); } bool CommandTagsCount::run() { m_vout << "Opening input file...\n"; osmium::io::Reader reader{m_input_file, osm_entity_bits(), osmium::io::read_meta::no}; m_vout << "Opening output file...\n"; int fd = 1; if (!m_output_filename.empty()) { fd = osmium::io::detail::open_for_writing(m_output_filename, m_output_overwrite); } m_vout << "Count matching keys/tags...\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()) { for (const auto& tag : object.tags()) { if (m_keys_filter(tag)) { ++m_counts[tag.key()]; } if (m_tags_filter(tag)) { ++m_counts[tag]; } } } } progress_bar.done(); m_vout << "Closing input file...\n"; reader.close(); show_memory_used(); m_vout << "Sorting results...\n"; const auto results = sort_results(); show_memory_used(); m_vout << "Writing results...\n"; write_results(results, fd); m_vout << "Done.\n"; return true; } osmium-tool-1.14.0/src/command_tags_count.hpp000066400000000000000000000106241420023413700212240ustar00rootroot00000000000000#ifndef COMMAND_TAGS_COUNT_HPP #define COMMAND_TAGS_COUNT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include #include #include #include #include #include #include #include #include /** * This class stores a key or key-value combination in a single std::string. * Key-value combinations are stored as key + \0 + value internally. */ class key_or_tag { std::string m_value; public: key_or_tag(const osmium::Tag& tag) : m_value(tag.key()) { m_value += '\0'; m_value += tag.value(); } key_or_tag(const char* key) : m_value(key) { } /// Return the key. const char* key() const noexcept { return m_value.c_str(); } /// Return value or nullptr if there is no value stored. const char* value() const noexcept { const auto pos = std::strlen(m_value.c_str()); if (pos == m_value.size()) { return nullptr; } return m_value.c_str() + pos + 1; } const std::string& get() const noexcept { return m_value; } friend bool operator==(const key_or_tag& a, const key_or_tag& b) noexcept { return a.get() == b.get(); } friend bool operator!=(const key_or_tag& a, const key_or_tag& b) noexcept { return a.get() != b.get(); } friend bool operator<(const key_or_tag& a, const key_or_tag& b) noexcept { return a.get() < b.get(); } friend bool operator<=(const key_or_tag& a, const key_or_tag& b) noexcept { return a.get() <= b.get(); } friend bool operator>(const key_or_tag& a, const key_or_tag& b) noexcept { return a.get() > b.get(); } friend bool operator>=(const key_or_tag& a, const key_or_tag& b) noexcept { return a.get() >= b.get(); } }; // class key_or_tag using counter_type = uint32_t; struct element_type { const key_or_tag* name; counter_type count; element_type(const key_or_tag& n, counter_type c) : name(&n), count(c) { } }; namespace std { template <> struct hash { std::size_t operator()(const key_or_tag& s) const noexcept { return std::hash{}(s.get()); } }; } // namespace std using sort_func_type = std::function; class CommandTagsCount : public CommandWithSingleOSMInput, public with_osm_output { osmium::TagsFilter m_keys_filter; osmium::TagsFilter m_tags_filter; std::string m_sort_order{"count-desc"}; sort_func_type m_sort_func; std::unordered_map m_counts; counter_type m_min_count = 0; counter_type m_max_count = std::numeric_limits::max(); void add_matcher(const std::string& expression); void read_expressions_file(const std::string& file_name); std::vector sort_results() const; public: explicit CommandTagsCount(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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-count"; } const char* synopsis() const noexcept override final { return "osmium tags-count [OPTIONS] OSM-FILE [TAG-EXPRESSION...]\n" " osmium tags-count [OPTIONS] --expressions=FILE OSM-FILE"; } }; // class CommandTagsCount #endif // COMMAND_TAGS_COUNT_HPP osmium-tool-1.14.0/src/command_tags_filter.cpp000066400000000000000000000347301420023413700213600ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_tags_filter.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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); } if (entities & osmium::osm_entity_bits::area) { m_area_filters.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") ("remove-tags,t", "Remove tags from non-matching 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); if (!setup_common(vm, desc)) { return false; } 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("remove-tags")) { m_remove_tags = 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 << " invert match: " << yes_no(m_invert_match); if (m_add_referenced_objects) { m_vout << " remove tags on non-matching objects: " << yes_no(m_remove_tags); } 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_area_filters.empty()); m_vout << " on relations: " << yes_no(!m_filters(osmium::item_type::relation).empty() || !m_area_filters.empty()); } osmium::osm_entity_bits::type CommandTagsFilter::get_needed_types() const { if (m_invert_match) { return osmium::osm_entity_bits::nwr; } osmium::osm_entity_bits::type types = osmium::osm_entity_bits::nothing; if (!m_referenced_ids(osmium::item_type::node).empty() || !m_filters(osmium::item_type::node).empty()) { types |= osmium::osm_entity_bits::node; } if (!m_referenced_ids(osmium::item_type::way).empty() || !m_filters(osmium::item_type::way).empty() || !m_area_filters.empty()) { types |= osmium::osm_entity_bits::way; } if (!m_referenced_ids(osmium::item_type::relation).empty() || !m_filters(osmium::item_type::relation).empty() || !m_area_filters.empty()) { types |= osmium::osm_entity_bits::relation; } return types; } void CommandTagsFilter::add_nodes(const osmium::Way& way) { for (const auto& nr : way.nodes()) { m_referenced_ids(osmium::item_type::node).set(nr.positive_ref()); } } void CommandTagsFilter::add_members(const osmium::Relation& relation) { for (const auto& member : relation.members()) { m_referenced_ids(member.type()).set(member.positive_ref()); } } bool CommandTagsFilter::matches_node(const osmium::Node& node) const noexcept { return osmium::tags::match_any_of(node.tags(), m_filters(osmium::item_type::node)); } bool CommandTagsFilter::matches_way(const osmium::Way& way) const noexcept { return osmium::tags::match_any_of(way.tags(), m_filters(osmium::item_type::way)) || (way.nodes().size() >= 4 && way.is_closed() && osmium::tags::match_any_of(way.tags(), m_area_filters)); } static bool is_multipolygon(const osmium::Relation& relation) noexcept { const char* type = relation.tags().get_value_by_key("type"); if (type == nullptr) { return false; } return !std::strcmp(type, "multipolygon") || !std::strcmp(type, "boundary"); } bool CommandTagsFilter::matches_relation(const osmium::Relation& relation) const noexcept { return osmium::tags::match_any_of(relation.tags(), m_filters(osmium::item_type::relation)) || (is_multipolygon(relation) && osmium::tags::match_any_of(relation.tags(), m_area_filters)); } bool CommandTagsFilter::matches_object(const osmium::OSMObject& object) const noexcept { switch (object.type()) { case osmium::item_type::node: return matches_node(static_cast(object)); case osmium::item_type::way: return matches_way(static_cast(object)); case osmium::item_type::relation: return matches_relation(static_cast(object)); default: break; } return false; } 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_referenced_ids(osmium::item_type::relation).check_and_set(member_id)) { mark_rel_ids(rel_in_rel, member_id); } }); } bool CommandTagsFilter::find_relations_in_relations() { m_vout << " Reading input file to find relations in relations...\n"; osmium::index::RelationsMapStash stash; ++m_count_passes; 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 (matches_relation(relation) != m_invert_match) { m_matching_ids(osmium::item_type::relation).set(relation.positive_id()); for (const auto& member : relation.members()) { if (member.type() == osmium::item_type::node) { m_referenced_ids(osmium::item_type::node).set(member.positive_ref()); } else if (member.type() == osmium::item_type::way) { m_referenced_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_matching_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"; ++m_count_passes; 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_referenced_ids(osmium::item_type::relation).get(relation.positive_id())) { for (const auto& member : relation.members()) { if (member.type() == osmium::item_type::node) { m_referenced_ids(osmium::item_type::node).set(member.positive_ref()); } else if (member.type() == osmium::item_type::way) { m_referenced_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"; ++m_count_passes; 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 (matches_way(way) != m_invert_match) { m_matching_ids(osmium::item_type::way).set(way.positive_id()); add_nodes(way); } else if (m_referenced_ids(osmium::item_type::way).get(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() || !m_area_filters.empty() || m_invert_match; if (todo) { todo = find_relations_in_relations(); } if (todo) { find_nodes_and_ways_in_relations(); } if (!m_referenced_ids(osmium::item_type::way).empty() || !m_filters(osmium::item_type::way).empty() || !m_area_filters.empty()) { find_nodes_in_ways(); } m_vout << "Done following references.\n"; } void CommandTagsFilter::copy_matching_objects(osmium::io::Reader& reader, osmium::io::Writer& writer) { m_vout << "Copying matching objects to output file...\n"; ++m_count_passes; 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 (m_matching_ids(object.type()).get(object.positive_id())) { writer(object); } else if ((!m_add_referenced_objects || object.type() == osmium::item_type::node) && matches_object(object) != m_invert_match) { writer(object); } else if (m_referenced_ids(object.type()).get(object.positive_id())) { if (m_remove_tags) { object.remove_tags(); } writer(object); } } } progress_bar.done(); m_vout << "Closing output file...\n"; writer.close(); m_vout << "Closing input file...\n"; reader.close(); } bool CommandTagsFilter::run() { if (m_add_referenced_objects) { m_vout << "Opening input file to get header...\n"; osmium::io::Reader reader_only_for_header{m_input_file, osmium::osm_entity_bits::nothing}; m_vout << "Opening output file...\n"; osmium::io::Header header{reader_only_for_header.header()}; setup_header(header); reader_only_for_header.close(); osmium::io::Writer writer{m_output_file, header, m_output_overwrite, m_fsync}; find_referenced_objects(); m_vout << "Opening input file...\n"; osmium::io::Reader reader{m_input_file, get_needed_types()}; copy_matching_objects(reader, writer); } else { 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}; copy_matching_objects(reader, writer); } show_memory_used(); m_vout << "Needed " << m_count_passes << " pass(es) through the input file.\n"; m_vout << "Done.\n"; return true; } osmium-tool-1.14.0/src/command_tags_filter.hpp000066400000000000000000000066171420023413700213700ustar00rootroot00000000000000#ifndef COMMAND_TAGS_FILTER_HPP #define COMMAND_TAGS_FILTER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include #include #include #include #include #include #include #include #include #include #include class CommandTagsFilter : public CommandWithSingleOSMInput, public with_osm_output { osmium::nwr_array m_filters; osmium::TagsFilter m_area_filters; osmium::nwr_array> m_matching_ids; osmium::nwr_array> m_referenced_ids; int m_count_passes = 0; bool m_add_referenced_objects = true; bool m_invert_match = false; bool m_remove_tags = false; 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); bool matches_node(const osmium::Node& node) const noexcept; bool matches_way(const osmium::Way& way) const noexcept; bool matches_relation(const osmium::Relation& relation) const noexcept; bool matches_object(const osmium::OSMObject& object) const noexcept; 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(); 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); void copy_matching_objects(osmium::io::Reader& reader, osmium::io::Writer& writer); public: explicit CommandTagsFilter(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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.14.0/src/command_time_filter.cpp000066400000000000000000000130471420023413700213560ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "command_time_filter.hpp" #include "exception.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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); if (!setup_common(vm, desc)) { return false; } setup_progress(vm); setup_input_file(vm); setup_output_file(vm); m_from = osmium::Timestamp{std::time(nullptr)}; 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::ReaderWithProgressBar reader{display_progress(), 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.14.0/src/command_time_filter.hpp000066400000000000000000000033571420023413700213660ustar00rootroot00000000000000#ifndef COMMAND_TIME_FILTER_HPP #define COMMAND_TIME_FILTER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" // IWYU pragma: export #include #include #include class CommandTimeFilter : public CommandWithSingleOSMInput, public with_osm_output { osmium::Timestamp m_from; osmium::Timestamp m_to; public: explicit CommandTimeFilter(const CommandFactory& command_factory) : CommandWithSingleOSMInput(command_factory) { } 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.14.0/src/commands.cpp000066400000000000000000000114141420023413700171520ustar00rootroot00000000000000 #include "cmd.hpp" #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_create_locations_index.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_getparents.hpp" #include "command_help.hpp" #include "command_merge.hpp" #include "command_merge_changes.hpp" #include "command_query_locations_index.hpp" #include "command_removeid.hpp" #include "command_renumber.hpp" #include "command_show.hpp" #include "command_sort.hpp" #include "command_tags_count.hpp" #include "command_tags_filter.hpp" #include "command_time_filter.hpp" void register_commands(CommandFactory& cmd_factory) { cmd_factory.register_command("add-locations-to-ways", "Add node locations to ways", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("apply-changes", "Apply OSM change files to OSM data file", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("cat", "Concatenate OSM files and convert to different formats", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("changeset-filter", "Filter OSM changesets by different criteria", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("check-refs", "Check referential integrity of an OSM file", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("create-locations-index", "Create node locations index on disk", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("derive-changes", "Create OSM change files from two OSM data files", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("diff", "Display differences between OSM files", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("export", "Export OSM data", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("extract", "Create geographic extract", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("fileinfo", "Show information about OSM file", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("getid", "Get objects with given ID from OSM file", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("getparents", "Get parents of objects from OSM file", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("help", "Show osmium help", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("merge-changes", "Merge several OSM change files into one", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("merge", "Merge several sorted OSM files into one", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("query-locations-index", "Query node locations index on disk", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("removeid", "Remove objects from OSM file by ID", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("renumber", "Renumber IDs in OSM file", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("show", "Show OSM file contents", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("sort", "Sort OSM data files", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("tags-count", "Count OSM tags", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("tags-filter", "Filter OSM data based on tags", [&]() { return std::make_unique(cmd_factory); }); cmd_factory.register_command("time-filter", "Filter OSM data from a point in time or a time span out of a history file", [&]() { return std::make_unique(cmd_factory); }); } osmium-tool-1.14.0/src/exception.hpp000066400000000000000000000035601420023413700173570ustar00rootroot00000000000000#ifndef EXCEPTION_HPP #define EXCEPTION_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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.14.0/src/export/000077500000000000000000000000001420023413700161655ustar00rootroot00000000000000osmium-tool-1.14.0/src/export/export_format.hpp000066400000000000000000000065261420023413700216000ustar00rootroot00000000000000#ifndef EXPORT_EXPORT_FORMAT_HPP #define EXPORT_EXPORT_FORMAT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "options.hpp" #include #include #include #include #include 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; virtual void debug_output(osmium::VerboseOutput& /*out*/, const std::string& /*filename*/) { } template bool add_tags(const osmium::OSMObject& object, TFunc&& func) { bool has_tags = false; for (const auto& tag : object.tags()) { if (options().tags_filter(tag)) { // If the tag key looks like any of the attribute keys, drop // the tag on the floor. This should be okay for most cases // when the attribute name chosen is sufficiently special. if (!options().type.empty() && tag.key() == options().type) { continue; } if (!options().id.empty() && tag.key() == options().id) { continue; } if (!options().version.empty() && tag.key() == options().version) { continue; } if (!options().changeset.empty() && tag.key() == options().changeset) { continue; } if (!options().uid.empty() && tag.key() == options().uid) { continue; } if (!options().user.empty() && tag.key() == options().user) { continue; } if (!options().timestamp.empty() && tag.key() == options().timestamp) { continue; } if (!options().way_nodes.empty() && tag.key() == options().way_nodes) { continue; } has_tags = true; std::forward(func)(tag); } } return has_tags; } }; // class ExportFormat #endif // EXPORT_EXPORT_FORMAT_HPP osmium-tool-1.14.0/src/export/export_format_json.cpp000066400000000000000000000144321420023413700226170ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "export_format_json.hpp" #include "../exception.hpp" #include "../util.hpp" #include static constexpr const std::size_t initial_buffer_size = 1024UL * 1024UL; static constexpr const std::size_t flush_buffer_size = 800UL * 1024UL; 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.format_options.is_true("print_record_separator")), 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(); if (output_format == "geojsonseq") { const auto prs = options.format_options.get("print_record_separator"); if (prs != "true" && prs != "false") { throw config_error{"Unknown value for print_record_separator option: '" + prs + "'."}; } } } 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); m_writer.String(object_type_as_string(object)); } 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.Int64(object.version()); } if (!options().changeset.empty()) { m_writer.String(options().changeset); m_writer.Int64(object.changeset()); } if (!options().uid.empty()) { m_writer.String(options().uid); m_writer.Int64(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.Int64(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(); } } void ExportFormatJSON::finish_feature(const osmium::OSMObject& object) { m_writer.Key("properties"); m_writer.StartObject(); // start properties add_attributes(object); const bool has_tags = add_tags(object, [&](const osmium::Tag& tag) { m_writer.String(tag.key()); m_writer.String(tag.value()); }); if (has_tags || 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.14.0/src/export/export_format_json.hpp000066400000000000000000000045061420023413700226250ustar00rootroot00000000000000#ifndef EXPORT_EXPORT_FORMAT_JSON_HPP #define EXPORT_EXPORT_FORMAT_JSON_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "export_format.hpp" #include #include #include #ifndef RAPIDJSON_HAS_STDSTRING # define RAPIDJSON_HAS_STDSTRING 1 #endif #include #include #include 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 = 0; 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); 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_EXPORT_FORMAT_JSON_HPP osmium-tool-1.14.0/src/export/export_format_pg.cpp000066400000000000000000000224661420023413700222620ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "export_format_pg.hpp" #include "../exception.hpp" #include "../util.hpp" #include #include #ifndef RAPIDJSON_HAS_STDSTRING # define RAPIDJSON_HAS_STDSTRING 1 #endif #include #include #include #include enum { initial_buffer_size = 1024U * 1024U }; enum { flush_buffer_size = 800U * 1024U }; ExportFormatPg::ExportFormatPg(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_buffer.reserve(initial_buffer_size); const auto tt = options.format_options.get("tags_type"); if (tt == "hstore") { m_tags_type = tags_output_format::hstore; } else if (tt == "json" || tt == "jsonb") { m_tags_type = tags_output_format::json; } else { throw config_error{"Unknown value for tags_format option: '" + tt + "'."}; } } void ExportFormatPg::flush_to_output() { osmium::io::detail::reliable_write(m_fd, m_buffer.data(), m_buffer.size()); m_buffer.clear(); m_commit_size = 0; } void ExportFormatPg::start_feature(const char type, const 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 += '\t'; } else if (options().unique_id == unique_id_type::type_id) { m_buffer += type; m_buffer.append(std::to_string(id)); m_buffer += '\t'; } } void ExportFormatPg::append_pg_escaped(const char* str, std::size_t size = std::numeric_limits::max()) { while (size-- > 0 && *str != '\0') { switch (*str) { case '\\': m_buffer += '\\'; m_buffer += '\\'; break; case '\n': m_buffer += '\\'; m_buffer += 'n'; break; case '\r': m_buffer += '\\'; m_buffer += 'r'; break; case '\t': m_buffer += '\\'; m_buffer += 't'; break; default: m_buffer += *str; } ++str; } } void ExportFormatPg::add_attributes(const osmium::OSMObject& object) { if (!options().type.empty()) { m_buffer.append(object_type_as_string(object)); m_buffer += '\t'; } if (!options().id.empty()) { m_buffer.append(std::to_string(object.type() == osmium::item_type::area ? osmium::area_id_to_object_id(object.id()) : object.id())); m_buffer += '\t'; } if (!options().version.empty()) { m_buffer.append(std::to_string(object.version())); m_buffer += '\t'; } if (!options().changeset.empty()) { m_buffer.append(std::to_string(object.changeset())); m_buffer += '\t'; } if (!options().uid.empty()) { m_buffer.append(std::to_string(object.uid())); m_buffer += '\t'; } if (!options().user.empty()) { append_pg_escaped(object.user()); m_buffer += '\t'; } if (!options().timestamp.empty()) { m_buffer.append(object.timestamp().to_iso()); m_buffer += '\t'; } if (!options().way_nodes.empty()) { if (object.type() == osmium::item_type::way) { m_buffer += '{'; for (const auto& nr : static_cast(object).nodes()) { m_buffer.append(std::to_string(nr.ref())); m_buffer += ','; } if (m_buffer.back() == ',') { m_buffer.back() = '}'; } else { m_buffer += '}'; } } else { m_buffer += '\\'; m_buffer += 'N'; } m_buffer += '\t'; } } bool ExportFormatPg::add_tags_json(const osmium::OSMObject& object) { bool has_tags = false; rapidjson::StringBuffer stream; rapidjson::Writer writer{stream}; writer.StartObject(); for (const auto& tag : object.tags()) { if (options().tags_filter(tag)) { has_tags = true; writer.Key(tag.key()); writer.String(tag.value()); } } writer.EndObject(); append_pg_escaped(stream.GetString(), stream.GetSize()); return has_tags; } static void add_escape_hstore(std::string* out, const char* str) { *out += "\""; while (*str) { if (*str == '"') { *out += "\\\""; } else if (*str == '\\') { *out += "\\\\"; } else { *out += *str; } ++str; } *out += "\""; } bool ExportFormatPg::add_tags_hstore(const osmium::OSMObject& object) { if (object.tags().empty()) { return false; } bool has_tags = false; std::string data; for (const auto& tag : object.tags()) { if (options().tags_filter(tag)) { has_tags = true; add_escape_hstore(&data, tag.key()); data += "=>"; add_escape_hstore(&data, tag.value()); data += ','; } } if (has_tags) { data.resize(data.size() - 1); append_pg_escaped(data.c_str()); } return has_tags; } bool ExportFormatPg::add_tags(const osmium::OSMObject& object) { return m_tags_type == tags_output_format::json ? add_tags_json(object) : add_tags_hstore(object); } void ExportFormatPg::finish_feature(const osmium::OSMObject& object) { m_buffer += '\t'; add_attributes(object); if (add_tags(object) || options().keep_untagged) { m_buffer += '\n'; m_commit_size = m_buffer.size(); ++m_count; if (m_buffer.size() > flush_buffer_size) { flush_to_output(); } } } void ExportFormatPg::node(const osmium::Node& node) { start_feature('n', node.id()); m_buffer.append(m_factory.create_point(node)); finish_feature(node); } void ExportFormatPg::way(const osmium::Way& way) { start_feature('w', way.id()); m_buffer.append(m_factory.create_linestring(way)); finish_feature(way); } void ExportFormatPg::area(const osmium::Area& area) { start_feature('a', area.id()); m_buffer.append(m_factory.create_multipolygon(area)); finish_feature(area); } void ExportFormatPg::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; } } void ExportFormatPg::debug_output(osmium::VerboseOutput& out, const std::string& filename) { out << '\n'; out << "Create table with something like this:\n"; if (m_tags_type == tags_output_format::hstore) { out << "CREATE EXTENSION IF NOT EXISTS hstore;\n"; } out << "CREATE TABLE osmdata (\n"; if (options().unique_id == unique_id_type::counter) { out << " id BIGINT PRIMARY KEY,\n"; } else if (options().unique_id == unique_id_type::type_id) { out << " id TEXT PRIMARY KEY,\n"; } out << " geom GEOMETRY, -- or GEOGRAPHY\n"; if (!options().type.empty()) { out << " osm_type TEXT,\n"; } if (!options().id.empty()) { out << " osm_id BIGINT,\n"; } if (!options().version.empty()) { out << " version INTEGER,\n"; } if (!options().changeset.empty()) { out << " changeset INTEGER,\n"; } if (!options().uid.empty()) { out << " uid INTEGER,\n"; } if (!options().user.empty()) { out << " \"user\" TEXT,\n"; } if (!options().timestamp.empty()) { out << " timestamp TIMESTAMP (0) WITH TIME ZONE,\n"; } if (!options().way_nodes.empty()) { out << " way_nodes BIGINT[],\n"; } switch (m_tags_type) { case tags_output_format::json: out << " tags JSONB -- or JSON, or TEXT\n"; break; case tags_output_format::hstore: out << " tags hstore\n"; break; } out << ");\n"; out << "Then load data with something like this:\n"; out << "\\copy osmdata FROM '" << filename << "'\n"; out << '\n'; } osmium-tool-1.14.0/src/export/export_format_pg.hpp000066400000000000000000000047311420023413700222620ustar00rootroot00000000000000#ifndef EXPORT_EXPORT_FORMAT_PG_HPP #define EXPORT_EXPORT_FORMAT_PG_HPP /* Osmium -- OpenStreetMap data manipulation command line tool http://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "export_format.hpp" #include #include #include #include class ExportFormatPg : public ExportFormat { enum tags_output_format { json, hstore }; osmium::geom::WKBFactory<> m_factory{osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex}; std::string m_buffer; std::size_t m_commit_size = 0; int m_fd; osmium::io::fsync m_fsync; tags_output_format m_tags_type = tags_output_format::json; void flush_to_output(); void start_feature(char type, osmium::object_id_type id); void add_attributes(const osmium::OSMObject& object); bool add_tags_json(const osmium::OSMObject& object); bool add_tags_hstore(const osmium::OSMObject& object); bool add_tags(const osmium::OSMObject& object); void finish_feature(const osmium::OSMObject& object); void append_pg_escaped(const char* str, std::size_t size); public: ExportFormatPg(const std::string& output_format, const std::string& output_filename, osmium::io::overwrite overwrite, osmium::io::fsync fsync, const options_type& options); ~ExportFormatPg() override { try { close(); } catch (...) { } } void node(const osmium::Node& node) override; void way(const osmium::Way& way) override; void area(const osmium::Area& area) override; void close() override; void debug_output(osmium::VerboseOutput& out, const std::string& filename) override; }; // class ExportFormatPg #endif // EXPORT_EXPORT_FORMAT_PG_HPP osmium-tool-1.14.0/src/export/export_format_spaten.cpp000066400000000000000000000244401420023413700231400ustar00rootroot00000000000000 #include "export_format_spaten.hpp" #include "../util.hpp" #include #include #include #include enum { // spaten block size, should be benchmarked initial_buffer_size = 15U * 1024U * 1024U }; enum { flush_buffer_size = 15U * 900U * 1024U }; enum { block_header_size = 8U }; static const char version[4] = {}; static const char flags[2] = {}; static const char compression = '\0'; static const char message_type = '\0'; static const char* const unique_id_field = "@fid"; static std::string uint64_buf(uint64_t v) { std::string buf(8, '\0'); buf[0] = static_cast((v ) & 0xffU); buf[1] = static_cast((v >> 8U) & 0xffU); buf[2] = static_cast((v >> 16U) & 0xffU); buf[3] = static_cast((v >> 24U) & 0xffU); buf[4] = static_cast((v >> 32U) & 0xffU); buf[5] = static_cast((v >> 40U) & 0xffU); buf[6] = static_cast((v >> 48U) & 0xffU); buf[7] = static_cast((v >> 56U) & 0xffU); return buf; } ExportFormatSpaten::ExportFormatSpaten(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) { write_file_header(); reserve_block_header_space(); m_buffer.reserve(initial_buffer_size); } void ExportFormatSpaten::write_file_header() const { std::string fh{"SPAT"}; fh.append(std::begin(version), std::end(version)); osmium::io::detail::reliable_write(m_fd, fh.data(), fh.size()); } void ExportFormatSpaten::reserve_block_header_space() { m_buffer.resize(m_buffer.size() + block_header_size); } void ExportFormatSpaten::start_feature(spaten_pbf::Geom gt, osmium::object_id_type id) { m_spaten_feature.add_enum(spaten_pbf::Feature::optional_Geom_geomtype, gt); m_spaten_feature.add_enum(spaten_pbf::Feature::optional_GeomSerial_geomserial, spaten_pbf::GeomSerial::wkb); if (options().unique_id == unique_id_type::counter) { std::string tagbuf; protozero::pbf_builder ptag{tagbuf}; ptag.add_string(spaten_pbf::Tag::optional_string_key, unique_id_field); ptag.add_string(spaten_pbf::Tag::optional_string_value, uint64_buf(m_count)); ptag.add_enum(spaten_pbf::Tag::optional_ValueType_type, spaten_pbf::TagValueType::uint64); m_spaten_feature.add_message(spaten_pbf::Feature::optional_Tag_tags, tagbuf); } else if (options().unique_id == unique_id_type::type_id) { std::string tagbuf; protozero::pbf_builder ptag{tagbuf}; char prefix = '\0'; if (gt == spaten_pbf::Geom::gt_node) { prefix = 'n'; } else if (gt == spaten_pbf::Geom::gt_line) { prefix = 'w'; } else if (gt == spaten_pbf::Geom::gt_poly) { prefix = 'a'; } ptag.add_string(spaten_pbf::Tag::optional_string_key, unique_id_field); ptag.add_string(spaten_pbf::Tag::optional_string_value, prefix + std::to_string(id)); ptag.add_enum(spaten_pbf::Tag::optional_ValueType_type, spaten_pbf::TagValueType::string); m_spaten_feature.add_message(spaten_pbf::Feature::optional_Tag_tags, tagbuf); } } void ExportFormatSpaten::node(const osmium::Node& node) { start_feature(spaten_pbf::Geom::gt_node, node.id()); m_spaten_feature.add_string(spaten_pbf::Feature::optional_string_geom, m_factory.create_point(node)); finish_feature(node); } void ExportFormatSpaten::way(const osmium::Way& way) { start_feature(spaten_pbf::Geom::gt_line, way.id()); m_spaten_feature.add_string(spaten_pbf::Feature::optional_string_geom, m_factory.create_linestring(way)); finish_feature(way); } void ExportFormatSpaten::area(const osmium::Area& area) { start_feature(spaten_pbf::Geom::gt_poly, area.id()); m_spaten_feature.add_string(spaten_pbf::Feature::optional_string_geom, m_factory.create_multipolygon(area)); finish_feature(area); } void ExportFormatSpaten::finish_feature(const osmium::OSMObject& object) { if (write_tags(object, m_spaten_feature) || options().keep_untagged) { m_spaten_block_body.add_message(spaten_pbf::Body::repeated_Feature_feature, m_feature_buffer); if (m_buffer.size() > flush_buffer_size) { flush_to_output(); } ++m_count; } m_feature_buffer.clear(); } void ExportFormatSpaten::add_attributes(const osmium::OSMObject& object, protozero::pbf_builder& proto_feat) { std::string tagbuf; protozero::pbf_builder ptag{tagbuf}; if (!options().type.empty()) { ptag.add_string(spaten_pbf::Tag::optional_string_key, options().type); ptag.add_string(spaten_pbf::Tag::optional_string_value, object_type_as_string(object)); ptag.add_enum(spaten_pbf::Tag::optional_ValueType_type, spaten_pbf::TagValueType::string); proto_feat.add_message(spaten_pbf::Feature::optional_Tag_tags, tagbuf); tagbuf.clear(); } if (!options().id.empty()) { ptag.add_string(spaten_pbf::Tag::optional_string_key, options().id); ptag.add_string(spaten_pbf::Tag::optional_string_value, uint64_buf(object.type() == osmium::item_type::area ? osmium::area_id_to_object_id(object.id()) : object.id())); ptag.add_enum(spaten_pbf::Tag::optional_ValueType_type, spaten_pbf::TagValueType::uint64); proto_feat.add_message(spaten_pbf::Feature::optional_Tag_tags, tagbuf); tagbuf.clear(); } if (!options().version.empty()) { ptag.add_string(spaten_pbf::Tag::optional_string_key, options().version); ptag.add_string(spaten_pbf::Tag::optional_string_value, uint64_buf(object.version())); ptag.add_enum(spaten_pbf::Tag::optional_ValueType_type, spaten_pbf::TagValueType::uint64); proto_feat.add_message(spaten_pbf::Feature::optional_Tag_tags, tagbuf); tagbuf.clear(); } if (!options().changeset.empty()) { ptag.add_string(spaten_pbf::Tag::optional_string_key, options().changeset); ptag.add_string(spaten_pbf::Tag::optional_string_value, uint64_buf(object.changeset())); ptag.add_enum(spaten_pbf::Tag::optional_ValueType_type, spaten_pbf::TagValueType::uint64); proto_feat.add_message(spaten_pbf::Feature::optional_Tag_tags, tagbuf); tagbuf.clear(); } if (!options().uid.empty()) { ptag.add_string(spaten_pbf::Tag::optional_string_key, options().uid); ptag.add_string(spaten_pbf::Tag::optional_string_value, uint64_buf(object.uid())); ptag.add_enum(spaten_pbf::Tag::optional_ValueType_type, spaten_pbf::TagValueType::uint64); proto_feat.add_message(spaten_pbf::Feature::optional_Tag_tags, tagbuf); tagbuf.clear(); } if (!options().user.empty()) { protozero::pbf_builder ptag{tagbuf}; ptag.add_string(spaten_pbf::Tag::optional_string_key, options().user); ptag.add_string(spaten_pbf::Tag::optional_string_value, object.user()); proto_feat.add_message(spaten_pbf::Feature::optional_Tag_tags, tagbuf); tagbuf.clear(); } if (!options().timestamp.empty()) { ptag.add_string(spaten_pbf::Tag::optional_string_key, options().timestamp); ptag.add_string(spaten_pbf::Tag::optional_string_value, uint64_buf(object.timestamp().seconds_since_epoch())); ptag.add_enum(spaten_pbf::Tag::optional_ValueType_type, spaten_pbf::TagValueType::uint64); proto_feat.add_message(spaten_pbf::Feature::optional_Tag_tags, tagbuf); tagbuf.clear(); } if (!options().way_nodes.empty() && object.type() == osmium::item_type::way) { std::string ways; ptag.add_string(spaten_pbf::Tag::optional_string_key, options().way_nodes); for (const auto& nr : static_cast(object).nodes()) { ways += std::to_string(nr.ref()); ways += ' '; } ways.resize(ways.size() - 1); ptag.add_string(spaten_pbf::Tag::optional_string_value, ways); proto_feat.add_message(spaten_pbf::Feature::optional_Tag_tags, tagbuf); tagbuf.clear(); } } bool ExportFormatSpaten::write_tags(const osmium::OSMObject& object, protozero::pbf_builder& proto_feat) { add_attributes(object, proto_feat); std::string tagbuf; const bool has_tags = add_tags(object, [&](const osmium::Tag& tag) { if (tag.key() == unique_id_field && options().unique_id != unique_id_type::none) { return; } protozero::pbf_builder ptag{tagbuf}; ptag.add_string(spaten_pbf::Tag::optional_string_key, tag.key()); ptag.add_string(spaten_pbf::Tag::optional_string_value, tag.value()); ptag.add_enum(spaten_pbf::Tag::optional_ValueType_type, spaten_pbf::TagValueType::string); proto_feat.add_message(spaten_pbf::Feature::optional_Tag_tags, tagbuf); tagbuf.clear(); }); return has_tags; } void ExportFormatSpaten::flush_to_output() { // static_cast okay. We flush the buffer long before it becomes to big. const auto buffer_size = static_cast(m_buffer.size() - block_header_size); std::string blockmeta(4, '\0'); blockmeta[0] = static_cast((buffer_size ) & 0xffU); blockmeta[1] = static_cast((buffer_size >> 8U) & 0xffU); blockmeta[2] = static_cast((buffer_size >> 16U) & 0xffU); blockmeta[3] = static_cast((buffer_size >> 24U) & 0xffU); blockmeta.append(std::begin(flags), std::end(flags)); blockmeta += compression; blockmeta += message_type; assert(blockmeta.size() == block_header_size); m_buffer.replace(0, blockmeta.size(), blockmeta); osmium::io::detail::reliable_write(m_fd, m_buffer.data(), m_buffer.size()); m_buffer.clear(); reserve_block_header_space(); } void ExportFormatSpaten::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.14.0/src/export/export_format_spaten.hpp000066400000000000000000000052501420023413700231430ustar00rootroot00000000000000#ifndef EXPORT_EXPORT_FORMAT_SPATEN_HPP #define EXPORT_EXPORT_FORMAT_SPATEN_HPP #include "export_format.hpp" #include #include #include #include #include namespace spaten_pbf { enum Geom : uint32_t { gt_node = 1, gt_line = 2, gt_poly = 3 }; enum GeomSerial : uint32_t { wkb = 0 }; enum TagValueType : uint32_t { string = 0, uint64 = 1, float64 = 2 }; enum class Body : protozero::pbf_tag_type { optional_Meta_meta = 1, repeated_Feature_feature = 2 }; enum class Feature : protozero::pbf_tag_type { optional_Geom_geomtype = 1, optional_GeomSerial_geomserial = 2, optional_string_geom = 3, optional_double_left = 4, optional_double_right = 5, optional_double_top = 6, optional_double_bottom = 7, optional_Tag_tags = 8 }; enum class Tag : protozero::pbf_tag_type { optional_string_key = 1, optional_string_value = 2, optional_ValueType_type = 3 }; } // namespace spaten_pbf class ExportFormatSpaten : public ExportFormat { osmium::geom::WKBFactory<> m_factory{osmium::geom::wkb_type::wkb, osmium::geom::out_type::binary}; std::string m_buffer; std::string m_feature_buffer; protozero::pbf_builder m_spaten_block_body{m_buffer}; protozero::pbf_builder m_spaten_feature{m_feature_buffer}; int m_fd; osmium::io::fsync m_fsync; void reserve_block_header_space(); void flush_to_output(); void write_file_header() const; bool write_tags(const osmium::OSMObject& object, protozero::pbf_builder& proto_feat); void add_attributes(const osmium::OSMObject& object, protozero::pbf_builder& proto_feat); void start_feature(spaten_pbf::Geom gt, osmium::object_id_type id); void finish_feature(const osmium::OSMObject& object); public: ExportFormatSpaten(const std::string& output_format, const std::string& output_filename, osmium::io::overwrite overwrite, osmium::io::fsync fsync, const options_type& options); ~ExportFormatSpaten() override { try { close(); } catch (...) { } } 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 ExportFormatSpaten #endif // EXPORT_EXPORT_FORMAT_SPATEN_HPP osmium-tool-1.14.0/src/export/export_format_text.cpp000066400000000000000000000132771420023413700226400ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "export_format_text.hpp" #include "../util.hpp" #include #include static constexpr const std::size_t initial_buffer_size = 1024UL * 1024UL; static constexpr const std::size_t flush_buffer_size = 800UL * 1024UL; 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_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, '='); m_buffer.append(object_type_as_string(object)); 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); } } } void ExportFormatText::finish_feature(const osmium::OSMObject& object) { m_buffer.append(1, ' '); add_attributes(object); const bool has_tags = add_tags(object, [&](const osmium::Tag& tag) { 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, ','); }); if (has_tags || 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.14.0/src/export/export_format_text.hpp000066400000000000000000000036751420023413700226460ustar00rootroot00000000000000#ifndef EXPORT_EXPORT_FORMAT_TEXT_HPP #define EXPORT_EXPORT_FORMAT_TEXT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "export_format.hpp" #include #include #include #include class ExportFormatText : public ExportFormat { osmium::geom::WKTFactory<> m_factory; std::string m_buffer; std::size_t m_commit_size = 0; 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); 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_EXPORT_FORMAT_TEXT_HPP osmium-tool-1.14.0/src/export/export_handler.cpp000066400000000000000000000106621420023413700217140ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "export_handler.hpp" #include "../exception.hpp" #include "../util.hpp" #include #include #include #include #include #include #include #include #include #include static bool check_conditions(const osmium::TagList& tags, const Ruleset& r1, const Ruleset& r2, bool is_no) noexcept { const char* area_tag = tags.get_value_by_key("area"); if (area_tag) { if (std::strcmp(area_tag, "no") == 0) { return is_no; } if (std::strcmp(area_tag, "yes") == 0) { return !is_no; } } if (r1.rule_type() == tags_filter_rule_type::other) { return osmium::tags::match_none_of(tags, r2.filter()); } return osmium::tags::match_any_of(tags, r1.filter()); } bool ExportHandler::is_linear(const osmium::TagList& tags) const noexcept { return check_conditions(tags, m_linear_ruleset, m_area_ruleset, true); } bool ExportHandler::is_area(const osmium::TagList& tags) const noexcept { return check_conditions(tags, m_area_ruleset, m_linear_ruleset, false); } ExportHandler::ExportHandler(std::unique_ptr&& handler, const Ruleset& linear_ruleset, const Ruleset& area_ruleset, geometry_types geometry_types, bool show_errors, bool stop_on_error) : m_handler(std::move(handler)), m_linear_ruleset(linear_ruleset), m_area_ruleset(area_ruleset), m_geometry_types(geometry_types), m_show_errors(show_errors), m_stop_on_error(stop_on_error) { } 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 (!m_geometry_types.point) { return; } 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 (!m_geometry_types.linestring) { return; } try { if (way.nodes().size() <= 1) { throw osmium::geometry_error{"Way with less than two nodes (id=" + std::to_string(way.id()) + ")"}; } if (!way.nodes().front().location() || !way.nodes().back().location()) { throw osmium::invalid_location{"invalid location"}; } if ((way.tags().empty() && m_handler->options().keep_untagged) || !way.ends_have_same_location() || is_linear(way.tags())) { 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 (!m_geometry_types.polygon) { return; } if (area.from_way() && !is_area(area.tags())) { return; } try { const auto rings = area.num_rings(); if (rings.first == 0 && rings.second == 0) { throw osmium::geometry_error{"Could not build area geometry"}; } 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.14.0/src/export/export_handler.hpp000066400000000000000000000044311420023413700217160ustar00rootroot00000000000000#ifndef EXPORT_EXPORT_HANDLER_HPP #define EXPORT_EXPORT_HANDLER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "export_format.hpp" #include "ruleset.hpp" #include #include #include #include #include #include #include #include #include class ExportHandler : public osmium::handler::Handler { std::unique_ptr m_handler; const Ruleset& m_linear_ruleset; const Ruleset& m_area_ruleset; uint64_t m_error_count = 0; geometry_types m_geometry_types; bool m_show_errors; bool m_stop_on_error; bool is_linear(const osmium::TagList& tags) const noexcept; bool is_area(const osmium::TagList& tags) const noexcept; void show_error(const std::runtime_error& error); public: ExportHandler(std::unique_ptr&& handler, const Ruleset& linear_ruleset, const Ruleset& area_ruleset, geometry_types geometry_types, 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.14.0/src/export/options.hpp000066400000000000000000000033241420023413700203730ustar00rootroot00000000000000#ifndef EXPORT_OPTIONS_HPP #define EXPORT_OPTIONS_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 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; osmium::Options format_options; bool keep_untagged = false; }; struct geometry_types { bool point = true; bool linestring = true; bool polygon = true; void clear() noexcept { point = false; linestring = false; polygon = false; } bool empty() const noexcept { return !point && !linestring && !polygon; } }; // struct geometry_types #endif // EXPORT_OPTIONS_HPP osmium-tool-1.14.0/src/export/ruleset.hpp000066400000000000000000000025711420023413700203660ustar00rootroot00000000000000#ifndef EXPORT_RULESET_HPP #define EXPORT_RULESET_HPP #include "../util.hpp" #include #include #include enum class tags_filter_rule_type { none = 0, any = 1, list = 2, other = 3 }; class Ruleset { tags_filter_rule_type m_type = tags_filter_rule_type::any; std::vector m_tags; osmium::TagsFilter m_filter{false}; public: void set_rule_type(tags_filter_rule_type type) noexcept { m_type = type; } tags_filter_rule_type rule_type() const noexcept { return m_type; } const std::vector& tags() const noexcept { return m_tags; } template void add_rule(T&& rule) { m_tags.emplace_back(std::forward(rule)); } const osmium::TagsFilter& filter() const noexcept { return m_filter; } void init_filter() { switch (m_type) { case tags_filter_rule_type::none: break; case tags_filter_rule_type::any: m_filter.set_default_result(true); break; case tags_filter_rule_type::list: initialize_tags_filter(m_filter, false, m_tags); break; case tags_filter_rule_type::other: break; } } }; // class Ruleset #endif // EXPORT_RULESET_HPP osmium-tool-1.14.0/src/extract/000077500000000000000000000000001420023413700163165ustar00rootroot00000000000000osmium-tool-1.14.0/src/extract/extract.cpp000066400000000000000000000034751420023413700205050ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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" #include #include #include #include void Extract::open_file(const osmium::io::Header& header, osmium::io::overwrite output_overwrite, osmium::io::fsync sync, OptionClean const* clean) { m_clean = clean; m_writer = std::make_unique(m_output_file, header, output_overwrite, sync); } void Extract::close_file() { if (m_writer) { if (m_buffer.committed() > 0) { m_clean->apply_to(m_buffer); (*m_writer)(std::move(m_buffer)); } m_writer->close(); } } void Extract::write(const osmium::memory::Item& item) { if (m_buffer.capacity() - m_buffer.committed() < item.padded_size()) { m_clean->apply_to(m_buffer); (*m_writer)(std::move(m_buffer)); m_buffer = osmium::memory::Buffer{buffer_size, osmium::memory::Buffer::auto_grow::no}; } m_buffer.push_back(item); } std::string Extract::envelope_as_text() const { std::stringstream ss; ss << m_envelope; return ss.str(); } osmium-tool-1.14.0/src/extract/extract.hpp000066400000000000000000000062271420023413700205100ustar00rootroot00000000000000#ifndef EXTRACT_EXTRACT_HPP #define EXTRACT_EXTRACT_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "../option_clean.hpp" #include #include #include #include #include #include #include #include #include #include #include class Extract { static constexpr const std::size_t buffer_size = 10UL * 1024UL * 1024UL; osmium::io::File m_output_file; std::string m_description; std::vector m_header_options; osmium::Box m_envelope; osmium::memory::Buffer m_buffer{buffer_size, osmium::memory::Buffer::auto_grow::no}; std::unique_ptr m_writer; const OptionClean* m_clean = nullptr; 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& option) { m_header_options.emplace_back(option + "!"); } 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, OptionClean const* clean); 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.14.0/src/extract/extract_bbox.cpp000066400000000000000000000024711420023413700215120ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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_bbox.hpp" #include #include 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.14.0/src/extract/extract_bbox.hpp000066400000000000000000000024771420023413700215250ustar00rootroot00000000000000#ifndef EXTRACT_EXTRACT_BBOX_HPP #define EXTRACT_EXTRACT_BBOX_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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.14.0/src/extract/extract_polygon.cpp000066400000000000000000000120101420023413700222350ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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_polygon.hpp" #include "../exception.hpp" #include #include #include #include #include #include #include #include #include static void add_ring(std::vector* segments, const osmium::NodeRefList& ring) { const auto* it = ring.begin(); const auto* const end = ring.end(); if (it == end) { throw config_error{"Ring without any points."}; } const auto* prev_it = it++; while (it != end) { segments->emplace_back(prev_it->location(), it->location()); prev_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) { // 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.14.0/src/extract/extract_polygon.hpp000066400000000000000000000034051420023413700222520ustar00rootroot00000000000000#ifndef EXTRACT_EXTRACT_POLYGON_HPP #define EXTRACT_EXTRACT_POLYGON_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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" #include #include #include class ExtractPolygon : public Extract { const osmium::memory::Buffer& m_buffer; std::size_t m_offset; std::vector> m_bands; int32_t m_dy = 0; 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.14.0/src/extract/geojson_file_parser.cpp000066400000000000000000000211231420023413700230400ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "geojson_file_parser.hpp" #include "../exception.hpp" #include "geometry_util.hpp" #include #include #include #include #include #include #include #include #include #include #include #include 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(); } 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.Empty()) { throw config_error{"Polygon must contain at least one ring."}; } { auto outer_ring = parse_ring(array[0]); if (!is_ccw(outer_ring)) { std::reverse(outer_ring.begin(), outer_ring.end()); } osmium::builder::OuterRingBuilder ring_builder{*builder}; for (const auto& c : outer_ring) { osmium::Location loc{c.x, c.y}; if (loc.valid()) { ring_builder.add_node_ref(0, loc); } else { throw config_error{"Invalid location in boundary (multi)polygon: (" + std::to_string(c.x) + ", " + std::to_string(c.y) + ")."}; } } } for (unsigned int i = 1; i < array.Size(); ++i) { auto inner_ring = parse_ring(array[i]); if (is_ccw(inner_ring)) { std::reverse(inner_ring.begin(), inner_ring.end()); } osmium::builder::InnerRingBuilder ring_builder{*builder}; for (const auto& c : inner_ring) { osmium::Location loc{c.x, c.y}; if (loc.valid()) { ring_builder.add_node_ref(0, loc); } else { throw config_error{"Invalid location in boundary (multi)polygon: (" + std::to_string(c.x) + ", " + std::to_string(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.Empty()) { 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(); } [[noreturn]] 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, std::string file_name) : m_buffer(buffer), m_file_name(std::move(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::parse_top(const rapidjson::Value& top) { const auto json_geometry = top.FindMember("geometry"); if (json_geometry == top.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); } return parse_multipolygon_array(json_coordinates->value, &m_buffer); } 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' or 'FeatureCollection'."); } if (type == "Feature") { return parse_top(doc); } if (type == "FeatureCollection") { const auto json_features = doc.FindMember("features"); if (json_features == doc.MemberEnd()) { error("Missing 'features' name."); } if (!json_features->value.IsArray()) { error("Expected 'features' value to be an array."); } const auto json_features_array = json_features->value.GetArray(); if (json_features_array.Empty()) { throw config_error{"Features array must contain at least one polygon."}; } const auto& json_first_feature = json_features_array[0]; if (!json_first_feature.IsObject()) { error("Expected values of 'features' array to be a objects."); } const std::string feature_type{get_value_as_string(json_first_feature, "type")}; if (feature_type != "Feature") { error("Expected 'type' value to be 'Feature'."); } return parse_top(json_first_feature); } error("Expected 'type' value to be 'Feature'."); } osmium-tool-1.14.0/src/extract/geojson_file_parser.hpp000066400000000000000000000032531420023413700230510ustar00rootroot00000000000000#ifndef EXTRACT_GEOJSON_FILE_PARSER_HPP #define EXTRACT_GEOJSON_FILE_PARSER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 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; [[noreturn]] void error(const std::string& message); std::size_t parse_top(const rapidjson::Value& top); public: GeoJSONFileParser(osmium::memory::Buffer& buffer, std::string file_name); std::size_t operator()(); }; // class GeoJSONFileParser #endif // EXTRACT_GEOJSON_FILE_PARSER_HPP osmium-tool-1.14.0/src/extract/geometry_util.cpp000066400000000000000000000014461420023413700217170ustar00rootroot00000000000000 #include "geometry_util.hpp" double calculate_double_area(const std::vector& coordinates) { assert(coordinates.size() > 1); double total = 0.0; auto prev = coordinates.front(); for (unsigned i = 1; i < coordinates.size(); ++i) { auto const cur = coordinates[i]; total += prev.lon() * cur.lat() - cur.lon() * prev.lat(); prev = cur; } return total; } double calculate_double_area(const std::vector& coordinates) { assert(coordinates.size() > 1); double total = 0.0; auto prev = coordinates.front(); for (unsigned i = 1; i < coordinates.size(); ++i) { auto const cur = coordinates[i]; total += prev.x * cur.y - cur.x * prev.y; prev = cur; } return total; } osmium-tool-1.14.0/src/extract/geometry_util.hpp000066400000000000000000000023731420023413700217240ustar00rootroot00000000000000#ifndef EXTRACT_GEOMETRY_UTIL_HPP #define EXTRACT_GEOMETRY_UTIL_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 double calculate_double_area(const std::vector& coordinates); double calculate_double_area(const std::vector& coordinates); /// Is the ring defined by the coordinates counter-clockwise? template bool is_ccw(T& coordinates) { return calculate_double_area(coordinates) > 0; } #endif // EXTRACT_GEOMETRY_UTIL_HPP osmium-tool-1.14.0/src/extract/osm_file_parser.cpp000066400000000000000000000061411420023413700221750ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "osm_file_parser.hpp" #include "../exception.hpp" #include #include #include #include #include #include #include #include #include #include using index_type = osmium::index::map::SparseMemArray; using location_handler_type = osmium::handler::NodeLocationsForWays; OSMFileParser::OSMFileParser(osmium::memory::Buffer& buffer, std::string file_name) : m_buffer(buffer), m_file_name(std::move(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; try { 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(); } catch (const osmium::invalid_location&) { throw config_error{"Invalid location in boundary (multi)polygon in '" + m_file_name + "'."}; } catch (const osmium::not_found&) { throw config_error{"Missing node in boundary (multi)polygon in '" + m_file_name + "'."}; } if (has_ring) { return m_buffer.commit(); } m_buffer.rollback(); throw osmium::io_error{"No areas found in the OSM file."}; } osmium-tool-1.14.0/src/extract/osm_file_parser.hpp000066400000000000000000000022721420023413700222030ustar00rootroot00000000000000#ifndef EXTRACT_OSM_FILE_PARSER_HPP #define EXTRACT_OSM_FILE_PARSER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 /** * Gets areas from OSM files. */ class OSMFileParser { osmium::memory::Buffer& m_buffer; std::string m_file_name; public: OSMFileParser(osmium::memory::Buffer& buffer, std::string file_name); std::size_t operator()(); }; // class OSMFileParser #endif // EXTRACT_OSM_FILE_PARSER_HPP osmium-tool-1.14.0/src/extract/poly_file_parser.cpp000066400000000000000000000105171420023413700223640ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "poly_file_parser.hpp" #include "../exception.hpp" #include "geometry_util.hpp" #include #include #include #include #include #include #include #include #include [[noreturn]] 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) { 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() { const bool is_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 (is_inner_ring) { if (is_ccw(coordinates)) { std::reverse(coordinates.begin(), coordinates.end()); } osmium::builder::InnerRingBuilder ring_builder{*m_builder}; for (const auto& location : coordinates) { ring_builder.add_node_ref(0, location); } } else { if (!is_ccw(coordinates)) { std::reverse(coordinates.begin(), coordinates.end()); } 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 = NAN; double lat = NAN; if (!(sstr >> lon >> lat)) { error("Expected coordinates or 'END' to end the ring."); } coordinates.emplace_back(lon, lat); if (!coordinates.back().valid()) { throw config_error{"Invalid location in boundary (multi)polygon: (" + std::to_string(lon) + ", " + std::to_string(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 = std::make_unique(m_buffer); while (m_line < m_data.size()) { parse_multipolygon(); } m_builder.reset(); return m_buffer.commit(); } osmium-tool-1.14.0/src/extract/poly_file_parser.hpp000066400000000000000000000036701420023413700223730ustar00rootroot00000000000000#ifndef EXTRACT_POLY_FILE_PARSER_HPP #define EXTRACT_POLY_FILE_PARSER_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 /** * 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: * https://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]; } [[noreturn]] 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.14.0/src/extract/strategy.hpp000066400000000000000000000111071420023413700206710ustar00rootroot00000000000000#ifndef EXTRACT_STRATEGY_HPP #define EXTRACT_STRATEGY_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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" #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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::VerboseOutput& /*vout*/) { } virtual void run(osmium::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) { assert(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.14.0/src/extract/strategy_complete_ways.cpp000066400000000000000000000145251420023413700236260ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "strategy_complete_ways.hpp" #include "../util.hpp" #include #include 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::Options& options) { m_extracts.reserve(extracts.size()); for (const auto& extract : extracts) { m_extracts.emplace_back(*extract); } for (const auto& option : options) { if (option.first != "relations") { warning(std::string{"Ignoring unknown option '"} + option.first + "' for 'complete_ways' strategy.\n"); } } if (options.is_false("relations")) { m_read_types = osmium::osm_entity_bits::node | osmium::osm_entity_bits::way; } } 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: explicit 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: explicit 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::VerboseOutput& vout, bool display_progress, const osmium::io::File& input_file) { if (input_file.filename().empty()) { throw osmium::io_error{"Can not read from STDIN when using 'complete_ways' strategy."}; } vout << "Running 'complete_ways' strategy in two passes...\n"; const std::size_t file_size = osmium::file_size(input_file.filename()); osmium::ProgressBar progress_bar{file_size * 2, display_progress}; vout << "First pass (of two)...\n"; Pass1 pass1{this}; pass1.run(progress_bar, input_file, osmium::io::read_meta::no, m_read_types); progress_bar.file_done(file_size); if (m_read_types & osmium::osm_entity_bits::relation) { // 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 (of two)...\n"; Pass2 pass2{this}; pass2.run(progress_bar, input_file, m_read_types); progress_bar.done(); } } // namespace strategy_complete_ways osmium-tool-1.14.0/src/extract/strategy_complete_ways.hpp000066400000000000000000000042771420023413700236360ustar00rootroot00000000000000#ifndef EXTRACT_STRATEGY_COMPLETE_WAYS_HPP #define EXTRACT_STRATEGY_COMPLETE_WAYS_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "strategy.hpp" #include #include #include #include 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; osmium::osm_entity_bits::type m_read_types = osmium::osm_entity_bits::nwr; public: explicit Strategy(const std::vector>& extracts, const osmium::Options& options); const char* name() const noexcept override final; void run(osmium::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.14.0/src/extract/strategy_complete_ways_with_history.cpp000066400000000000000000000143511420023413700264370ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "strategy_complete_ways_with_history.hpp" #include #include 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::Options& /*options*/) { 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: explicit 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: explicit 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::VerboseOutput& vout, bool display_progress, const osmium::io::File& input_file) { if (input_file.filename().empty()) { throw osmium::io_error{"Can not read from STDIN when using 'complete_ways' strategy."}; } vout << "Running 'complete_ways' strategy on history file in two passes...\n"; const std::size_t file_size = osmium::file_size(input_file.filename()); osmium::ProgressBar progress_bar{file_size * 2, display_progress}; vout << "First pass (of two)...\n"; Pass1 pass1{this}; pass1.run(progress_bar, input_file); 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 (of two)...\n"; Pass2 pass2{this}; pass2.run(progress_bar, input_file); progress_bar.done(); } } // namespace strategy_complete_ways_with_history osmium-tool-1.14.0/src/extract/strategy_complete_ways_with_history.hpp000066400000000000000000000042601420023413700264420ustar00rootroot00000000000000#ifndef EXTRACT_STRATEGY_COMPLETE_WAYS_WITH_HISTORY_HPP #define EXTRACT_STRATEGY_COMPLETE_WAYS_WITH_HISTORY_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "strategy.hpp" #include #include #include #include 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::Options& /*options*/); const char* name() const noexcept override final; void run(osmium::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.14.0/src/extract/strategy_simple.cpp000066400000000000000000000072071420023413700222430ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "strategy_simple.hpp" #include "../util.hpp" #include namespace strategy_simple { Strategy::Strategy(const std::vector>& extracts, const osmium::Options& options) { 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: explicit 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::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 = input_file.filename().empty() ? 0 : osmium::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.14.0/src/extract/strategy_simple.hpp000066400000000000000000000034011420023413700222400ustar00rootroot00000000000000#ifndef EXTRACT_STRATEGY_SIMPLE_HPP #define EXTRACT_STRATEGY_SIMPLE_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "strategy.hpp" #include #include #include 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::Options& /*options*/); const char* name() const noexcept override final; void run(osmium::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.14.0/src/extract/strategy_smart.cpp000066400000000000000000000246411420023413700221010ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "strategy_smart.hpp" #include "../util.hpp" #include #include #include namespace strategy_smart { void Data::add_relation_members(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::Options& options) { m_extracts.reserve(extracts.size()); for (const auto& extract : extracts) { m_extracts.emplace_back(*extract); } m_types = {"multipolygon"}; for (const auto& option : options) { if (option.first == "types") { if (option.second.empty() || option.second == "any" || option.second == "true") { m_types.clear(); } else { m_types = osmium::split_string(option.second, ',', true); } } else if (option.first == "complete-partial-relations") { if (!option.second.empty()) { m_complete_partial_relations_percentage = osmium::detail::str_to_int(option.second.c_str()); if (m_complete_partial_relations_percentage <= 0 || m_complete_partial_relations_percentage > 100) { m_complete_partial_relations_percentage = 100; } } } else { warning(std::string{"Ignoring unknown option '"} + option.first + "' for 'smart' strategy.\n"); } } } const char* Strategy::name() const noexcept { return "smart"; } bool Strategy::check_members_count(const std::size_t size, const std::size_t wanted_members) const noexcept { return wanted_members * 100 >= size * m_complete_partial_relations_percentage; } 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::VerboseOutput& vout) { vout << "Additional strategy options:\n"; if (m_types.empty()) { vout << " - [types] relation types: any\n"; } else { std::string typelist; for (const auto& type : m_types) { if (!typelist.empty()) { typelist += ", "; } typelist += type; } vout << " - [types] relation types: " << typelist << '\n'; } if (m_complete_partial_relations_percentage == 100) { vout << " - [complete-partial-relations] do not complete partial relations\n"; } else { vout << " - [complete-partial-relations] complete partial relations when " << m_complete_partial_relations_percentage << "% or more members are in extract\n"; } vout << '\n'; } class Pass1 : public Pass { osmium::handler::CheckOrder m_check_order; osmium::index::RelationsMapStash m_relations_map_stash; public: explicit 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) { std::size_t wanted_members = 0; for (const auto& member : relation.members()) { switch (member.type()) { case osmium::item_type::node: if (e->node_ids.get(member.positive_ref())) { if (wanted_members == 0) { e->relation_ids.set(relation.positive_id()); if (strategy().check_type(relation)) { e->add_relation_members(relation); return; } } ++wanted_members; } break; case osmium::item_type::way: if (e->way_ids.get(member.positive_ref())) { if (wanted_members == 0) { e->relation_ids.set(relation.positive_id()); if (strategy().check_type(relation)) { e->add_relation_members(relation); return; } } ++wanted_members; } break; default: break; } } if (strategy().check_members_count(relation.members().size(), wanted_members)) { e->add_relation_members(relation); } } osmium::index::RelationsMapStash& relations_map_stash() noexcept { return m_relations_map_stash; } }; // class Pass1 class Pass2 : public Pass { public: explicit 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: explicit 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::VerboseOutput& vout, bool display_progress, const osmium::io::File& input_file) { if (input_file.filename().empty()) { throw osmium::io_error{"Can not read from STDIN when using 'smart' strategy."}; } vout << "Running 'smart' strategy in three passes...\n"; const std::size_t file_size = osmium::file_size(input_file.filename()); osmium::ProgressBar progress_bar{file_size * 3, display_progress}; vout << "First pass (of three)...\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 (of three)...\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 (of three)...\n"; Pass3 pass3{this}; pass3.run(progress_bar, input_file); progress_bar.done(); } } // namespace strategy_smart osmium-tool-1.14.0/src/extract/strategy_smart.hpp000066400000000000000000000052631420023413700221050ustar00rootroot00000000000000#ifndef EXTRACT_STRATEGY_SMART_HPP #define EXTRACT_STRATEGY_SMART_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "strategy.hpp" #include #include #include #include #include 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_members(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; std::size_t m_complete_partial_relations_percentage = 100; bool check_members_count(const std::size_t size, const std::size_t wanted_members) const noexcept; bool check_type(const osmium::Relation& relation) const noexcept; public: explicit Strategy(const std::vector>& extracts, const osmium::Options& options); const char* name() const noexcept override final; void show_arguments(osmium::VerboseOutput& vout) override final; void run(osmium::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.14.0/src/id_file.cpp000066400000000000000000000033511420023413700167450ustar00rootroot00000000000000 #include "id_file.hpp" #include "util.hpp" #include #include #include #include #include void add_nodes(const osmium::Way& way, ids_type& ids) { for (const auto& nr : way.nodes()) { ids(osmium::item_type::node).set(nr.positive_ref()); } } void read_id_osm_file(const std::string& file_name, ids_type& ids) { osmium::io::Reader reader{file_name, osmium::osm_entity_bits::object}; while (osmium::memory::Buffer buffer = reader.read()) { for (const auto& object : buffer.select()) { ids(object.type()).set(object.positive_id()); } } reader.close(); } void parse_and_add_id(const std::string& s, ids_type& ids, osmium::item_type default_item_type) { auto p = osmium::string_to_object_id(s.c_str(), osmium::osm_entity_bits::nwr, default_item_type); if (p.second < 0) { throw std::runtime_error{"This command does not work with negative IDs"}; } ids(p.first).set(static_cast(p.second)); } void read_id_file(std::istream& stream, ids_type& ids, osmium::item_type default_item_type) { 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, ids, default_item_type); } } } bool no_ids(const ids_type& ids) noexcept { return ids(osmium::item_type::node).empty() && ids(osmium::item_type::way).empty() && ids(osmium::item_type::relation).empty(); } osmium-tool-1.14.0/src/id_file.hpp000066400000000000000000000013111420023413700167440ustar00rootroot00000000000000#ifndef ID_FILES_HPP #define ID_FILES_HPP #include #include #include #include #include #include using ids_type = osmium::nwr_array>; void add_nodes(const osmium::Way& way, ids_type& ids); void read_id_osm_file(const std::string& file_name, ids_type& ids); void parse_and_add_id(const std::string& s, ids_type& ids, osmium::item_type default_item_type); void read_id_file(std::istream& stream, ids_type& ids, osmium::item_type default_item_type); bool no_ids(const ids_type& ids) noexcept; #endif // ID_FILES_HPP osmium-tool-1.14.0/src/io.cpp000066400000000000000000000171571420023413700157720ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" #include "exception.hpp" #include "util.hpp" #include // IWYU pragma: keep #include // IWYU pragma: keep #include #include #include #include #include #include #include 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.empty()) { 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::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.emplace_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::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.empty()) { 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::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); } } void init_header(osmium::io::Header& header, const osmium::io::Header& input_header, const std::vector& options) { for (const auto& h : options) { if (!h.empty() && h.back() == '!') { std::string hc{h}; hc.resize(h.size() - 1); header.set(hc, input_header.get(hc)); } else { header.set(h); } } } void with_osm_output::setup_header(osmium::io::Header& header, const osmium::io::Header& input_header) const { header.set("generator", m_generator); init_header(header, input_header, m_output_headers); } osmium-tool-1.14.0/src/main.cpp000066400000000000000000000115051420023413700162760ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "cmd.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 # include # include #endif enum return_code : int { okay = 0, error = 1, fatal = 2 }; int main(int argc, char* argv[]) { #ifdef _WIN32 _setmode(1, _O_BINARY); #endif 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.empty()) { 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' << "Supported PBF compression types:"; for (const auto& type : osmium::io::supported_pbf_compression_types()) { std::cout << " " << type; } std::cout << "\n\nCopyright (C) 2013-2022 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; } CommandFactory command_factory; register_commands(command_factory); std::unique_ptr cmd = command_factory.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&) { 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.14.0/src/option_clean.cpp000066400000000000000000000062071420023413700200270ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "option_clean.hpp" #include "exception.hpp" #include #include void OptionClean::setup(const boost::program_options::variables_map& vm) { if (vm.count("clean")) { for (const auto& c : vm["clean"].as>()) { if (c == "version") { m_clean_attrs |= clean_options::clean_version; } else if (c == "changeset") { m_clean_attrs |= clean_options::clean_changeset; } else if (c == "timestamp") { m_clean_attrs |= clean_options::clean_timestamp; } else if (c == "uid") { m_clean_attrs |= clean_options::clean_uid; } else if (c == "user") { m_clean_attrs |= clean_options::clean_user; } else { throw argument_error{"Unknown attribute on --clean option: '" + c + "'"}; } } } } void OptionClean::clean_buffer(osmium::memory::Buffer& buffer) const { for (auto& object : buffer.select()) { if (m_clean_attrs & clean_options::clean_version) { object.set_version(static_cast(0)); } if (m_clean_attrs & clean_options::clean_changeset) { object.set_changeset(static_cast(0)); } if (m_clean_attrs & clean_options::clean_timestamp) { object.set_timestamp(osmium::Timestamp{}); } if (m_clean_attrs & clean_options::clean_uid) { object.set_uid(static_cast(0)); } if (m_clean_attrs & clean_options::clean_user) { object.clear_user(); } } } std::string OptionClean::to_string() const { if (!m_clean_attrs) { return "(none)"; } std::string clean_names; if (m_clean_attrs & clean_options::clean_version) { clean_names += "version,"; } if (m_clean_attrs & clean_options::clean_changeset) { clean_names += "changeset,"; } if (m_clean_attrs & clean_options::clean_timestamp) { clean_names += "timestamp,"; } if (m_clean_attrs & clean_options::clean_uid) { clean_names += "uid,"; } if (m_clean_attrs & clean_options::clean_user) { clean_names += "user,"; } clean_names.resize(clean_names.size() - 1); return clean_names; } osmium-tool-1.14.0/src/option_clean.hpp000066400000000000000000000030321420023413700200250ustar00rootroot00000000000000#ifndef OPTION_CLEAN_HPP #define OPTION_CLEAN_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 class OptionClean { enum clean_options : uint8_t { clean_version = 0x01, clean_changeset = 0x02, clean_timestamp = 0x04, clean_uid = 0x08, clean_user = 0x10 }; uint8_t m_clean_attrs = 0; void clean_buffer(osmium::memory::Buffer& buffer) const; public: OptionClean() = default; void setup(const boost::program_options::variables_map& vm); void apply_to(osmium::memory::Buffer& buffer) const { if (m_clean_attrs) { clean_buffer(buffer); } } std::string to_string() const; }; // class OptionClean #endif // OPTION_CLEAN_HPP osmium-tool-1.14.0/src/util.cpp000066400000000000000000000171231420023413700163310ustar00rootroot00000000000000/* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 "util.hpp" #include "exception.hpp" #include #include #include #include #include #include #include #include #include #include /** * 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(const osmium::io::File& file) { if (file.filename().empty()) { return 0; } return osmium::file_size(file.filename()); } std::size_t file_size_sum(const std::vector& files) { std::size_t sum = 0; for (const auto& file : files) { sum += file_size(file); } 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; case 'a': entities |= osmium::osm_entity_bits::area; break; default: throw argument_error{std::string{"Unknown object type '"} + c + "' (allowed are 'n', 'w', 'r', and 'a')."}; } } 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, bool* has_value_matcher) { const auto op_pos = expression.find('='); if (op_pos == std::string::npos) { if (has_value_matcher) { *has_value_matcher = false; } 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; } if (has_value_matcher) { *has_value_matcher = true; } return osmium::TagMatcher{get_string_matcher(key), get_string_matcher(value), invert}; } void initialize_tags_filter(osmium::TagsFilter& tags_filter, const 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{"Need exactly four coordinates in " + option_name + " option."}; } osmium::Location location1; location1.set_lon(coordinates[0].c_str()); location1.set_lat(coordinates[1].c_str()); osmium::Location location2; location2.set_lon(coordinates[2].c_str()); location2.set_lat(coordinates[3].c_str()); osmium::Box box; box.extend(location1); box.extend(location2); if (!box.valid()) { throw argument_error{"Invalid bounding box in " + option_name + " option. Format is LONG1,LAT1,LONG2,LAT2."}; } return box; } osmium::item_type parse_item_type(const std::string& t) { if (t == "n" || t == "node") { return osmium::item_type::node; } if (t == "w" || t == "way") { return osmium::item_type::way; } if (t == "r" || t == "relation") { return osmium::item_type::relation; } throw argument_error{std::string{"Unknown default type '"} + t + "' (Allowed are 'node', 'way', and 'relation')."}; } const char* object_type_as_string(const osmium::OSMObject& object) noexcept { if (object.type() == osmium::item_type::area) { if (static_cast(object).from_way()) { return "way"; } return "relation"; } return osmium::item_type_to_name(object.type()); } bool ends_with(const std::string& str, const std::string& suffix) { if (suffix.size() > str.size()) { return false; } return std::strcmp(str.c_str() + (str.size() - suffix.size()), suffix.c_str()) == 0; } std::size_t show_mbytes(std::size_t value) noexcept { return value / (1024UL * 1024UL); } double show_gbytes(std::size_t value) noexcept { return static_cast(show_mbytes(value)) / 1000; // NOLINT(bugprone-integer-division) } osmium-tool-1.14.0/src/util.hpp000066400000000000000000000044001420023413700163300ustar00rootroot00000000000000#ifndef UTIL_HPP #define UTIL_HPP /* Osmium -- OpenStreetMap data manipulation command line tool https://osmcode.org/osmium-tool/ Copyright (C) 2013-2022 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 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(const osmium::io::File& file); std::size_t file_size_sum(const std::vector& files); osmium::osm_entity_bits::type get_types(const std::string& str); std::pair get_filter_expression(const std::string& str); void strip_whitespace(std::string& string); osmium::StringMatcher get_string_matcher(std::string string); osmium::TagMatcher get_tag_matcher(const std::string& expression, bool* has_value_matcher = nullptr); 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); osmium::item_type parse_item_type(const std::string& t); const char* object_type_as_string(const osmium::OSMObject& object) noexcept; bool ends_with(const std::string& str, const std::string& suffix); std::size_t show_mbytes(std::size_t value) noexcept; double show_gbytes(std::size_t value) noexcept; #endif // UTIL_HPP osmium-tool-1.14.0/src/version.cpp.in000066400000000000000000000005201420023413700174370ustar00rootroot00000000000000 #include const char* get_osmium_version() noexcept { return "@PROJECT_VERSION@"; } const char* get_osmium_long_version() noexcept { return "osmium version @PROJECT_VERSION@@VERSION_FROM_GIT@"; } const char* get_libosmium_version() noexcept { return "libosmium version " LIBOSMIUM_VERSION_STRING; } osmium-tool-1.14.0/test/000077500000000000000000000000001420023413700150345ustar00rootroot00000000000000osmium-tool-1.14.0/test/CMakeLists.txt000066400000000000000000000071151420023413700176000ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests # #----------------------------------------------------------------------------- include_directories(include) include_directories(../src) include_directories(../src/extract) include_directories(../include) set(ALL_UNIT_TESTS cat/test_setup.cpp diff/test_setup.cpp extract/test_unit.cpp time-filter/test_setup.cpp util/test_unit.cpp ) foreach(_source_file ${OSMIUM_SOURCE_FILES}) list(APPEND ALL_COMMANDS "../src/${_source_file}") endforeach() 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}") if(ARGC GREATER 4) set(_return_code "${ARGV4}") else() set(_return_code 0) endif() 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} -D return_code=${_return_code} -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} -D return_code=0 -P ${CMAKE_SOURCE_DIR}/cmake/run_test_compare_output.cmake ) endfunction() #----------------------------------------------------------------------------- # # Configure tests for all commands # #----------------------------------------------------------------------------- foreach(_cmd IN LISTS OSMIUM_COMMANDS) do_test(help_cmd_${_cmd} "osmium ${_cmd} -h" "Usage: osmium ${_cmd}.*OPTIONS:") if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_cmd}/CMakeLists.txt") message(STATUS "Adding tests in ${_cmd}") add_subdirectory(${_cmd}) else() message(STATUS "No tests for ${_cmd} command found") endif() endforeach() foreach(_extra_tests formats help misc) message(STATUS "Adding tests in ${_extra_tests}") add_subdirectory(${_extra_tests}) endforeach() #----------------------------------------------------------------------------- osmium-tool-1.14.0/test/add-locations-to-ways/000077500000000000000000000000001420023413700211565ustar00rootroot00000000000000osmium-tool-1.14.0/test/add-locations-to-ways/CMakeLists.txt000066400000000000000000000015101420023413700237130ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # 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-header=xml_josm_upload=false --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) check_add_locations_to_ways(membernodes "--keep-member-nodes" input-rel.osm output-rel.osm) #----------------------------------------------------------------------------- osmium-tool-1.14.0/test/add-locations-to-ways/input-rel.osm000066400000000000000000000016771420023413700236300ustar00rootroot00000000000000 osmium-tool-1.14.0/test/add-locations-to-ways/input.osm000066400000000000000000000020701420023413700230340ustar00rootroot00000000000000 osmium-tool-1.14.0/test/add-locations-to-ways/output-n.osm000066400000000000000000000022241420023413700234710ustar00rootroot00000000000000 osmium-tool-1.14.0/test/add-locations-to-ways/output-rel.osm000066400000000000000000000013711420023413700240200ustar00rootroot00000000000000 osmium-tool-1.14.0/test/add-locations-to-ways/output.osm000066400000000000000000000013201420023413700232320ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/000077500000000000000000000000001420023413700175675ustar00rootroot00000000000000osmium-tool-1.14.0/test/apply-changes/CMakeLists.txt000066400000000000000000000072511420023413700223340ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # 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) #----------------------------------------------------------------------------- # Test some patching features useful to redact existing OSM files #----------------------------------------------------------------------------- # Version 1 contains a copyright violation. The diff file contains a v2 object (with visible=false) and a modified v1 object. check_apply_changes(redact-and-update "--redact" input-redact-and-update.osh input-redact-and-update.osc "osh" output-redact-and-update.osh) # The input history file contains version 1 and 2, the diff wants to replace v1 by a deleted object (to redact the sensitive data in v1). # The output history file should contain the redacted version 1 and an unmodified copy of v2. check_apply_changes(patch-old-version "--redact" input-patch-old-version.osh input-patch-old-version.osc "osh" output-patch-old-version.osh) # The input history file contains version 1 and 2 of an object. The diff wants to remove the metadata of v1. Version 2 should stay untouched. check_apply_changes(redact-metadata "--redact" input-redact-metadata.osh input-redact-metadata.osc "osh" output-redact-metadata.osh) #----------------------------------------------------------------------------- # Test the application of diffs which have only some metadata fields on files which have only some metadata fields #----------------------------------------------------------------------------- # The input file has version and timestamp fields, the diff has only version fields. check_apply_changes(version-on-version-timestamp "" input-version+timestamp.osm input-version.osc "osm" output-version-applied-on-version+timestamp.osm) check_apply_changes(version-on-version-timestamp-low "--locations-on-ways" input-version+timestamp.osm input-version.osc "osm" output-version-applied-on-version+timestamp-low.osm) # The input file has all metadata fields, the diff has only version fields. check_apply_changes(version-on-all "" input-data.osm input-change-only-version.osc "osm" output-version-applied-on-all.osm) osmium-tool-1.14.0/test/apply-changes/input-change-only-version.osc000066400000000000000000000006771420023413700253330ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/input-change.osc000066400000000000000000000013131420023413700226550ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/input-data-low.osm000066400000000000000000000022521420023413700231550ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/input-data.osm000066400000000000000000000021321420023413700223530ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/input-history.osh000066400000000000000000000023131420023413700231370ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/input-history.osm000066400000000000000000000023131420023413700231440ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/input-patch-old-version.osc000066400000000000000000000003551420023413700247730ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/input-patch-old-version.osh000066400000000000000000000020541420023413700247760ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/input-redact-and-update.osc000066400000000000000000000005501420023413700247140ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/input-redact-and-update.osh000066400000000000000000000006341420023413700247240ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/input-redact-metadata.osc000066400000000000000000000004611420023413700244530ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/input-redact-metadata.osh000066400000000000000000000011031420023413700244520ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/input-version+timestamp.osm000066400000000000000000000016511420023413700251330ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/input-version.osc000066400000000000000000000010501420023413700231130ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/output-data-low.osm000066400000000000000000000022271420023413700233600ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/output-data.osm000066400000000000000000000021071420023413700225560ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/output-history.osh000066400000000000000000000035511420023413700233450ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/output-patch-old-version.osh000066400000000000000000000017011420023413700251750ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/output-redact-and-update.osh000066400000000000000000000006731420023413700251300ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/output-redact-metadata.osh000066400000000000000000000010271420023413700246600ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/output-version-applied-on-all.osm000066400000000000000000000015761420023413700261370ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/output-version-applied-on-version+timestamp-low.osm000066400000000000000000000016551420023413700316500ustar00rootroot00000000000000 osmium-tool-1.14.0/test/apply-changes/output-version-applied-on-version+timestamp.osm000066400000000000000000000015021420023413700310400ustar00rootroot00000000000000 osmium-tool-1.14.0/test/cat/000077500000000000000000000000001420023413700156035ustar00rootroot00000000000000osmium-tool-1.14.0/test/cat/CMakeLists.txt000066400000000000000000000021241420023413700203420ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # 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(osm input1.osm output1.osm.opl opl) check_convert(gzip input1.osm.gz output1.osm.opl opl) check_convert(bzip2 input1.osm.bz2 output1.osm.opl opl) check_convert(pbf input1.osm.pbf output1.osm.opl opl) check_convert(opl output1.osm.opl output1.osm.opl opl) #----------------------------------------------------------------------------- osmium-tool-1.14.0/test/cat/input1.osm000066400000000000000000000006661420023413700175530ustar00rootroot00000000000000 osmium-tool-1.14.0/test/cat/input1.osm.bz2000066400000000000000000000003531420023413700202400ustar00rootroot00000000000000BZh91AY&SYôÐ*û\_€PƒûW/çß@0ÙAšš@hhÐ 42d ŒA‰“CL ¨…<©é=¢e?SIú¦Fƒ&ŽaÈkŒ’]XëÜáT²Í˞ΔbæÈö­f±#Õ¥S—äŒKŽM@ŘIÃȤœ$,–ÛÈD€gÐ3'%³0k²­­CtÔ(w&?£M,kÙ4Á)çÅÊx –FÛ¦Çéà¸Âb¤K±ŒUOè$»(À¹®FRJV\êg½‘Hz )£¤éh–d#Ÿø»’)„‡¦WØosmium-tool-1.14.0/test/cat/input1.osm.gz000066400000000000000000000003151420023413700201610ustar00rootroot00000000000000‹›‹úVinput1.osmµ‘»Â0 E÷~Eä%SKÒ „PÒn|AYآƔJyTMŠø|"¨x Œ•®dËö½g°hîÖNaðNR^0JÐu^®—ôÔó=mêLø`ßWÀŠN*úIBĵРÈ<¯´„‹2¡ÎÎk$Cšqø$¤>6Ù”%”ŒosÆ“ZÆŒ%SÖbš. ÝU¹Æçƨ¥¾"7¿¼r^ùW­Ã«¾yb“QgÈJ¾¶osmium-tool-1.14.0/test/cat/input1.osm.pbf000066400000000000000000000002431420023413700203100ustar00rootroot00000000000000 OSMHeader7+3xœSâó/Î NÎHÍMÔ 3Ð3SârIÍ+NõËOI-nbäÉ/ÎÍ,ÍÕ7Ô³Ô3#P + OSMDataLMHxœãâàbàb)I-.r²çbfbbÒ’åbfddb_ðaÉ).)f&%¡"œxná„a/6ÉÀÄÌÀÀosmium-tool-1.14.0/test/cat/input2.osm000066400000000000000000000006661420023413700175540ustar00rootroot00000000000000 osmium-tool-1.14.0/test/cat/output-cat12.osm000066400000000000000000000013631420023413700205760ustar00rootroot00000000000000 osmium-tool-1.14.0/test/cat/output-cat21.osm000066400000000000000000000013631420023413700205760ustar00rootroot00000000000000 osmium-tool-1.14.0/test/cat/output1.osm.opl000066400000000000000000000002311420023413700205310ustar00rootroot00000000000000n1 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.14.0/test/cat/test_setup.cpp000066400000000000000000000053451420023413700205150ustar00rootroot00000000000000 #include "test.hpp" // IWYU pragma: keep #include "command_cat.hpp" TEST_CASE("cat") { CommandFactory factory; CommandCat cmd{factory}; 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().empty()); auto of = cmd.output_file(); REQUIRE(of.format() == osmium::io::file_format::pbf); REQUIRE(of.filename().empty()); 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.14.0/test/changeset-filter/000077500000000000000000000000001420023413700202605ustar00rootroot00000000000000osmium-tool-1.14.0/test/changeset-filter/CMakeLists.txt000066400000000000000000000123131420023413700230200ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # 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) check_changeset_filter(cf1-bbox01 "--bbox 120,-11,121,-10" input1.osm output1-first.osm) check_changeset_filter(cf1-bbox02 "--bbox 130,-31,131,-30" input1.osm output-empty.osm) #----------------------------------------------------------------------------- osmium-tool-1.14.0/test/changeset-filter/input-open.osm000066400000000000000000000005271420023413700231020ustar00rootroot00000000000000 osmium-tool-1.14.0/test/changeset-filter/input1.osm000066400000000000000000000012131420023413700222150ustar00rootroot00000000000000 osmium-tool-1.14.0/test/changeset-filter/output-empty.osm000066400000000000000000000001231420023413700234700ustar00rootroot00000000000000 osmium-tool-1.14.0/test/changeset-filter/output-open.osm000066400000000000000000000005421420023413700233000ustar00rootroot00000000000000 osmium-tool-1.14.0/test/changeset-filter/output1-all.osm000066400000000000000000000012471420023413700231730ustar00rootroot00000000000000 osmium-tool-1.14.0/test/changeset-filter/output1-first.osm000066400000000000000000000006211420023413700235450ustar00rootroot00000000000000 osmium-tool-1.14.0/test/changeset-filter/output1-second.osm000066400000000000000000000005511420023413700236730ustar00rootroot00000000000000 osmium-tool-1.14.0/test/check-refs/000077500000000000000000000000001420023413700170465ustar00rootroot00000000000000osmium-tool-1.14.0/test/check-refs/CMakeLists.txt000066400000000000000000000055501420023413700216130ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # 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.14.0/test/check-refs/fail-n-in-r.osm000066400000000000000000000004031420023413700215740ustar00rootroot00000000000000 osmium-tool-1.14.0/test/check-refs/fail-n-in-w.osm000066400000000000000000000007261420023413700216110ustar00rootroot00000000000000 osmium-tool-1.14.0/test/check-refs/fail-r-in-r-1.osm000066400000000000000000000004071420023413700217420ustar00rootroot00000000000000 osmium-tool-1.14.0/test/check-refs/fail-r-in-r-2.osm000066400000000000000000000004071420023413700217430ustar00rootroot00000000000000 osmium-tool-1.14.0/test/check-refs/fail-w-in-r.osm000066400000000000000000000004021420023413700216040ustar00rootroot00000000000000 osmium-tool-1.14.0/test/check-refs/okay-r-in-r.osm000066400000000000000000000006501420023413700216340ustar00rootroot00000000000000 osmium-tool-1.14.0/test/check-refs/okay.osm000066400000000000000000000017061420023413700205350ustar00rootroot00000000000000 osmium-tool-1.14.0/test/check-refs/way-okay.osm000066400000000000000000000014411420023413700213270ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/000077500000000000000000000000001420023413700177205ustar00rootroot00000000000000osmium-tool-1.14.0/test/derive-changes/CMakeLists.txt000066400000000000000000000033471420023413700224670ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # 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) # Tests with input file which don't have the same amount of metadata fields: # File 1 has all metadata fields, file 2 has only version fields. check_derive_changes(new_file_only_versions "" input1.osm input2-only-versions.osm output-2-only-version.osc) # File 1 has only version and timestamp fields, file 2 has only version fields. check_derive_changes(version_timestamp_with_version "" input1-only-version-timestamp.osm input2-only-versions.osm output-2-only-version-timestamp.osc) # File 1 has only version fields, file 2 has version and timestamp fields. check_derive_changes(version_with_version_timestamp "" input1-only-version.osm input2-only-version-timestamp.osm output-2-version-with-version-timestamp.osc) # File 1 has only version fields, file 2 has all metadata fields. check_derive_changes(version_with_all "" input1-only-version.osm input2-all-with-relation.osm output-2-version-with-all.osc) #----------------------------------------------------------------------------- osmium-tool-1.14.0/test/derive-changes/input1-only-version-timestamp.osm000066400000000000000000000016201420023413700263220ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/input1-only-version.osm000066400000000000000000000013431420023413700243230ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/input1.osm000066400000000000000000000021761420023413700216660ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/input2-all-with-relation.osm000066400000000000000000000021471420023413700252170ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/input2-only-version-timestamp.osm000066400000000000000000000016401420023413700263250ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/input2-only-versions.osm000066400000000000000000000011621420023413700245060ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/input2.osm000066400000000000000000000021071420023413700216610ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/output-2-only-version-timestamp.osc000066400000000000000000000007141420023413700265720ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/output-2-only-version.osc000066400000000000000000000007141420023413700245710ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/output-2-version-with-all.osc000066400000000000000000000013511420023413700253270ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/output-2-version-with-version-timestamp.osc000066400000000000000000000012051420023413700302430ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/output-incr-version.osc000066400000000000000000000012251420023413700244020ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/output-keep-details.osc000066400000000000000000000013571420023413700243410ustar00rootroot00000000000000 osmium-tool-1.14.0/test/derive-changes/output.osc000066400000000000000000000012251420023413700217660ustar00rootroot00000000000000 osmium-tool-1.14.0/test/diff/000077500000000000000000000000001420023413700157445ustar00rootroot00000000000000osmium-tool-1.14.0/test/diff/CMakeLists.txt000066400000000000000000000014551420023413700205110ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - diff # #----------------------------------------------------------------------------- function(check_diff _name _options _input1 _input2 _output _return_code) check_output(diff ${_name} "diff ${_options} diff/${_input1} diff/${_input2}" "diff/${_output}" "${_return_code}") endfunction() check_diff(compact "" input1.osm input2.osm output-compact 1) check_diff(compact-c "-c" input1.osm input2.osm output-compact-c 1) check_diff(opl "-f opl" input1.osm input2.osm output.opl 1) check_diff(opl-c "-f opl -c" input1.osm input2.osm output-c.opl 1) check_diff(same "" input1.osm input1.osm output-same 0) #----------------------------------------------------------------------------- osmium-tool-1.14.0/test/diff/input1.osm000066400000000000000000000024741420023413700177130ustar00rootroot00000000000000 osmium-tool-1.14.0/test/diff/input2.osm000066400000000000000000000024511420023413700177070ustar00rootroot00000000000000 osmium-tool-1.14.0/test/diff/output-c.opl000066400000000000000000000010461420023413700202410ustar00rootroot00000000000000-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.14.0/test/diff/output-compact000066400000000000000000000001401420023413700206460ustar00rootroot00000000000000 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.14.0/test/diff/output-compact-c000066400000000000000000000001001420023413700210620ustar00rootroot00000000000000-n11 v1 +n11 v2 -n13 v1 +n14 v1 *n15 v1 *n16 v1 -w21 v1 +w21 v2 osmium-tool-1.14.0/test/diff/output-same000066400000000000000000000001101420023413700201420ustar00rootroot00000000000000 n10 v1 n11 v1 n12 v1 n13 v1 n15 v1 n16 v1 w20 v1 w21 v1 r30 v1 osmium-tool-1.14.0/test/diff/output.opl000066400000000000000000000014211420023413700200160ustar00rootroot00000000000000 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.14.0/test/diff/test_setup.cpp000066400000000000000000000020211420023413700206420ustar00rootroot00000000000000 #include "test.hpp" #include "command_diff.hpp" TEST_CASE("diff") { CommandFactory factory; CommandDiff cmd{factory}; 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.14.0/test/export/000077500000000000000000000000001420023413700163555ustar00rootroot00000000000000osmium-tool-1.14.0/test/export/CMakeLists.txt000066400000000000000000000077521420023413700211300ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # 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 -x print_record_separator=false" input.osm output.geojsonseq) check_export(spaten "-f spaten" input.osm output.spaten) check_export(missing-node "-f geojson" input-missing-node.osm output-missing-node.geojson) check_export(single-node-way "-f geojson" input-single-node-way.osm output-empty.geojson) add_test(NAME export-error-node COMMAND osmium export -f geojson -E ${CMAKE_SOURCE_DIR}/test/export/input-missing-node.osm) set_tests_properties(export-error-node PROPERTIES WILL_FAIL true) add_test(NAME export-error-single-node-way COMMAND osmium export -f geojson -E ${CMAKE_SOURCE_DIR}/test/export/input-single-node-way.osm) set_tests_properties(export-error-single-node-way PROPERTIES WILL_FAIL true) check_export(invalid-area "-f geojson" input-incomplete-relation.osm output-incomplete-relation.geojson) add_test(NAME export-error-area COMMAND osmium export -f geojson -E ${CMAKE_SOURCE_DIR}/test/export/input-incomplete-relation.osm) set_tests_properties(export-error-area PROPERTIES WILL_FAIL true) add_test(NAME export-error-incomplete-rel COMMAND osmium export -f geojson -E ${CMAKE_SOURCE_DIR}/test/export/input-incomplete-rel-missing-way.osm) set_tests_properties(export-error-incomplete-rel PROPERTIES WILL_FAIL true) #----------------------------------------------------------------------------- check_export(attributes "-E -f text -a id" way.osm way-all.txt) check_export(c-empty-empty-n "-E -f text --keep-untagged -c export/config-empty-empty.json" way.osm way-all-n.txt) set_tests_properties(export-c-empty-empty-n PROPERTIES ENVIRONMENT osmium_cmake_stderr=ignore) check_export(c-empty-empty "-E -f text -c export/config-empty-empty.json" way.osm way-all.txt) set_tests_properties(export-c-empty-empty PROPERTIES ENVIRONMENT osmium_cmake_stderr=ignore) check_export(c-null-null "-E -f text -c export/config-null-null.json" way.osm way-all.txt) check_export(c-undefined "-E -f text -c export/config-undefined.json" way.osm way-all.txt) check_export(c-tag-empty "-E -f text -c export/config-tag-empty.json" way.osm way-tag-empty.txt) set_tests_properties(export-c-tag-empty PROPERTIES ENVIRONMENT osmium_cmake_stderr=ignore) check_export(c-empty-tag "-E -f text -c export/config-empty-tag.json" way.osm way-empty-tag.txt) set_tests_properties(export-c-empty-tag PROPERTIES ENVIRONMENT osmium_cmake_stderr=ignore) check_export(c-tag-tag "-E -f text -c export/config-tag-tag.json" way.osm way-tag-tag.txt) check_export(c-tagx-empty "-E -f text -c export/config-tagx-empty.json" way.osm way-tagx-empty.txt) set_tests_properties(export-c-tagx-empty PROPERTIES ENVIRONMENT osmium_cmake_stderr=ignore) check_export(c-empty-tagx "-E -f text -c export/config-empty-tagx.json" way.osm way-empty-tagx.txt) set_tests_properties(export-c-empty-tagx PROPERTIES ENVIRONMENT osmium_cmake_stderr=ignore) check_export(c-tagx-tagx "-E -f text -c export/config-tagx-tagx.json" way.osm way-tagx-tagx.txt) check_export(c-true-true "-E -f text -c export/config-true-true.json" way.osm way-all.txt) check_export(c-false-false "-E -f text -c export/config-false-false.json" way.osm way-none.txt) check_export(c-null-tag "-E -f text -c export/config-null-tag.json" way.osm way-null-tag.txt) check_export(c-tag-null "-E -f text -c export/config-tag-null.json" way.osm way-tag-null.txt) #----------------------------------------------------------------------------- check_export(spaten-untagged "-f spaten --keep-untagged" input.osm output-untagged.spaten) #----------------------------------------------------------------------------- osmium-tool-1.14.0/test/export/config-empty-empty.json000066400000000000000000000005341420023413700230070ustar00rootroot00000000000000{ "attributes": { "type": false, "id": true, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": [], "area_tags": [], "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/test/export/config-empty-tag.json000066400000000000000000000005451420023413700224260ustar00rootroot00000000000000{ "attributes": { "type": false, "id": true, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": [], "area_tags": ["landuse"], "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/test/export/config-empty-tagx.json000066400000000000000000000005541420023413700226160ustar00rootroot00000000000000{ "attributes": { "type": false, "id": true, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": [], "area_tags": ["does-not-exist"], "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/test/export/config-false-false.json000066400000000000000000000005421420023413700226760ustar00rootroot00000000000000{ "attributes": { "type": false, "id": true, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": false, "area_tags": false, "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/test/export/config-null-null.json000066400000000000000000000005401420023413700224340ustar00rootroot00000000000000{ "attributes": { "type": false, "id": true, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": null, "area_tags": null, "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/test/export/config-null-tag.json000066400000000000000000000005471420023413700222440ustar00rootroot00000000000000{ "attributes": { "type": false, "id": true, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": null, "area_tags": ["landuse"], "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/test/export/config-tag-empty.json000066400000000000000000000005451420023413700224260ustar00rootroot00000000000000{ "attributes": { "type": false, "id": true, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": ["barrier"], "area_tags": [], "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/test/export/config-tag-null.json000066400000000000000000000005151420023413700222370ustar00rootroot00000000000000{ "attributes": { "type": false, "id": true, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": ["barrier"], "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/test/export/config-tag-tag.json000066400000000000000000000005561420023413700220450ustar00rootroot00000000000000{ "attributes": { "type": false, "id": true, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": ["barrier"], "area_tags": ["landuse"], "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/test/export/config-tagx-empty.json000066400000000000000000000005541420023413700226160ustar00rootroot00000000000000{ "attributes": { "type": false, "id": true, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": ["does-not-exist"], "area_tags": [], "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/test/export/config-tagx-tagx.json000066400000000000000000000005741420023413700224250ustar00rootroot00000000000000{ "attributes": { "type": false, "id": true, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": ["does-not-exist"], "area_tags": ["does-not-exist"], "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/test/export/config-true-true.json000066400000000000000000000005401420023413700224460ustar00rootroot00000000000000{ "attributes": { "type": false, "id": true, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "linear_tags": true, "area_tags": true, "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/test/export/config-undefined.json000066400000000000000000000004541420023413700224570ustar00rootroot00000000000000{ "attributes": { "type": false, "id": true, "version": false, "changeset": false, "timestamp": false, "uid": false, "user": false, "way_nodes": false }, "exclude_tags": [], "include_tags": [] } osmium-tool-1.14.0/test/export/empty-tag.txt000066400000000000000000000013551420023413700210310ustar00rootroot00000000000000LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=31,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=32,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=33,barrier=fence,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=34,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=35,area=something MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=31,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=32,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=33,barrier=fence,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=35,area=something MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=36,area=yes osmium-tool-1.14.0/test/export/input-incomplete-rel-missing-way.osm000066400000000000000000000015611420023413700254210ustar00rootroot00000000000000 osmium-tool-1.14.0/test/export/input-incomplete-relation.osm000066400000000000000000000027041420023413700242070ustar00rootroot00000000000000 osmium-tool-1.14.0/test/export/input-missing-node.osm000066400000000000000000000026021420023413700226260ustar00rootroot00000000000000 osmium-tool-1.14.0/test/export/input-single-node-way.osm000066400000000000000000000005631420023413700232400ustar00rootroot00000000000000 osmium-tool-1.14.0/test/export/input.osm000066400000000000000000000027631420023413700202440ustar00rootroot00000000000000 osmium-tool-1.14.0/test/export/output-empty.geojson000066400000000000000000000000551420023413700224370ustar00rootroot00000000000000{"type":"FeatureCollection","features":[ ]} osmium-tool-1.14.0/test/export/output-incomplete-relation.geojson000066400000000000000000000006371420023413700252610ustar00rootroot00000000000000{"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.14.0/test/export/output-missing-node.geojson000066400000000000000000000006601420023413700236770ustar00rootroot00000000000000{"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.14.0/test/export/output-untagged.spaten000066400000000000000000000010061420023413700227220ustar00rootroot00000000000000SPATöð?ð?ð?@ð?@ð?@2@ø?B amenitypost_boxS9ð?ð?ð?@ð?@B highwaytrackS9ð?ð?ð?@@ø?B barrierfence/)@ø?ð?ð?qVð?ð?@ø?ð?@ð?ð?B landuseforestosmium-tool-1.14.0/test/export/output.geojson000066400000000000000000000010641420023413700213040ustar00rootroot00000000000000{"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.14.0/test/export/output.geojsonseq000066400000000000000000000010051420023413700220100ustar00rootroot00000000000000{"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.14.0/test/export/output.spaten000066400000000000000000000005411420023413700211310ustar00rootroot00000000000000SPATQ2@ø?B amenitypost_boxS9ð?ð?ð?@ð?@B highwaytrackS9ð?ð?ð?@@ø?B barrierfenceqVð?ð?@ø?ð?@ð?ð?B landuseforestosmium-tool-1.14.0/test/export/tag-empty.txt000066400000000000000000000013551420023413700210310ustar00rootroot00000000000000LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=31,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=32,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=33,barrier=fence,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=34,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=35,area=something MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=31,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=32,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=33,barrier=fence,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=35,area=something MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=36,area=yes osmium-tool-1.14.0/test/export/tag-tag.txt000066400000000000000000000013551420023413700204460ustar00rootroot00000000000000LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=31,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=32,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=33,barrier=fence,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=34,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=35,area=something MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=31,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=32,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=33,barrier=fence,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=35,area=something MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=36,area=yes osmium-tool-1.14.0/test/export/way-all-n.txt000066400000000000000000000033471420023413700207260ustar00rootroot00000000000000POINT(1 1) @id=10 POINT(1 2) @id=11 POINT(2 2) @id=12 POINT(2 1) @id=13 LINESTRING(1 1,1 2,2 2) @id=20 LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2) @id=25,area=no,barrier=fence LINESTRING(1 1,1 2,2 2) @id=26,area=something,barrier=fence LINESTRING(1 1,1 2,2 2) @id=27,area=yes,barrier=fence LINESTRING(1 1,1 2,2 2) @id=28,area=no,landuse=grass LINESTRING(1 1,1 2,2 2) @id=29,area=something,landuse=grass LINESTRING(1 1,1 2,2 2) @id=30,area=yes,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=40 LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=41,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=42,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=43,barrier=fence,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=44,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=45,area=something LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=47,area=no,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=48,area=something,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=50,area=no,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=51,area=something,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=41,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=42,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=43,barrier=fence,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=45,area=something MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=46,area=yes MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=48,area=something,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=49,area=yes,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=51,area=something,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=52,area=yes,landuse=grass osmium-tool-1.14.0/test/export/way-all.txt000066400000000000000000000031311420023413700204620ustar00rootroot00000000000000LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2) @id=25,area=no,barrier=fence LINESTRING(1 1,1 2,2 2) @id=26,area=something,barrier=fence LINESTRING(1 1,1 2,2 2) @id=27,area=yes,barrier=fence LINESTRING(1 1,1 2,2 2) @id=28,area=no,landuse=grass LINESTRING(1 1,1 2,2 2) @id=29,area=something,landuse=grass LINESTRING(1 1,1 2,2 2) @id=30,area=yes,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=41,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=42,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=43,barrier=fence,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=44,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=45,area=something LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=47,area=no,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=48,area=something,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=50,area=no,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=51,area=something,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=41,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=42,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=43,barrier=fence,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=45,area=something MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=46,area=yes MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=48,area=something,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=49,area=yes,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=51,area=something,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=52,area=yes,landuse=grass osmium-tool-1.14.0/test/export/way-empty-tag.txt000066400000000000000000000026301420023413700216240ustar00rootroot00000000000000LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2) @id=25,area=no,barrier=fence LINESTRING(1 1,1 2,2 2) @id=26,area=something,barrier=fence LINESTRING(1 1,1 2,2 2) @id=27,area=yes,barrier=fence LINESTRING(1 1,1 2,2 2) @id=28,area=no,landuse=grass LINESTRING(1 1,1 2,2 2) @id=29,area=something,landuse=grass LINESTRING(1 1,1 2,2 2) @id=30,area=yes,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=41,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=42,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=43,barrier=fence,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=44,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=45,area=something LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=47,area=no,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=48,area=something,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=50,area=no,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=51,area=something,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=42,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=43,barrier=fence,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=46,area=yes MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=49,area=yes,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=51,area=something,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=52,area=yes,landuse=grass osmium-tool-1.14.0/test/export/way-empty-tagx.txt000066400000000000000000000023121420023413700220110ustar00rootroot00000000000000LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2) @id=25,area=no,barrier=fence LINESTRING(1 1,1 2,2 2) @id=26,area=something,barrier=fence LINESTRING(1 1,1 2,2 2) @id=27,area=yes,barrier=fence LINESTRING(1 1,1 2,2 2) @id=28,area=no,landuse=grass LINESTRING(1 1,1 2,2 2) @id=29,area=something,landuse=grass LINESTRING(1 1,1 2,2 2) @id=30,area=yes,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=41,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=42,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=43,barrier=fence,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=44,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=45,area=something LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=47,area=no,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=48,area=something,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=50,area=no,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=51,area=something,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=46,area=yes MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=49,area=yes,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=52,area=yes,landuse=grass osmium-tool-1.14.0/test/export/way-none.txt000066400000000000000000000015371420023413700206610ustar00rootroot00000000000000LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2) @id=25,area=no,barrier=fence LINESTRING(1 1,1 2,2 2) @id=26,area=something,barrier=fence LINESTRING(1 1,1 2,2 2) @id=27,area=yes,barrier=fence LINESTRING(1 1,1 2,2 2) @id=28,area=no,landuse=grass LINESTRING(1 1,1 2,2 2) @id=29,area=something,landuse=grass LINESTRING(1 1,1 2,2 2) @id=30,area=yes,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=44,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=47,area=no,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=50,area=no,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=46,area=yes MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=49,area=yes,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=52,area=yes,landuse=grass osmium-tool-1.14.0/test/export/way-null-tag.txt000066400000000000000000000023341420023413700214410ustar00rootroot00000000000000LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2) @id=25,area=no,barrier=fence LINESTRING(1 1,1 2,2 2) @id=26,area=something,barrier=fence LINESTRING(1 1,1 2,2 2) @id=27,area=yes,barrier=fence LINESTRING(1 1,1 2,2 2) @id=28,area=no,landuse=grass LINESTRING(1 1,1 2,2 2) @id=29,area=something,landuse=grass LINESTRING(1 1,1 2,2 2) @id=30,area=yes,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=41,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=44,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=45,area=something LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=47,area=no,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=48,area=something,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=50,area=no,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=42,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=43,barrier=fence,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=46,area=yes MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=49,area=yes,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=51,area=something,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=52,area=yes,landuse=grass osmium-tool-1.14.0/test/export/way-tag-empty.txt000066400000000000000000000026521420023413700216300ustar00rootroot00000000000000LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2) @id=25,area=no,barrier=fence LINESTRING(1 1,1 2,2 2) @id=26,area=something,barrier=fence LINESTRING(1 1,1 2,2 2) @id=27,area=yes,barrier=fence LINESTRING(1 1,1 2,2 2) @id=28,area=no,landuse=grass LINESTRING(1 1,1 2,2 2) @id=29,area=something,landuse=grass LINESTRING(1 1,1 2,2 2) @id=30,area=yes,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=41,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=43,barrier=fence,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=44,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=47,area=no,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=48,area=something,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=50,area=no,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=41,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=42,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=43,barrier=fence,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=45,area=something MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=46,area=yes MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=48,area=something,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=49,area=yes,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=51,area=something,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=52,area=yes,landuse=grass osmium-tool-1.14.0/test/export/way-tag-null.txt000066400000000000000000000023341420023413700214410ustar00rootroot00000000000000LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2) @id=25,area=no,barrier=fence LINESTRING(1 1,1 2,2 2) @id=26,area=something,barrier=fence LINESTRING(1 1,1 2,2 2) @id=27,area=yes,barrier=fence LINESTRING(1 1,1 2,2 2) @id=28,area=no,landuse=grass LINESTRING(1 1,1 2,2 2) @id=29,area=something,landuse=grass LINESTRING(1 1,1 2,2 2) @id=30,area=yes,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=41,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=43,barrier=fence,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=44,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=47,area=no,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=48,area=something,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=50,area=no,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=42,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=45,area=something MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=46,area=yes MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=49,area=yes,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=51,area=something,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=52,area=yes,landuse=grass osmium-tool-1.14.0/test/export/way-tag-tag.txt000066400000000000000000000023511420023413700212410ustar00rootroot00000000000000LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2) @id=25,area=no,barrier=fence LINESTRING(1 1,1 2,2 2) @id=26,area=something,barrier=fence LINESTRING(1 1,1 2,2 2) @id=27,area=yes,barrier=fence LINESTRING(1 1,1 2,2 2) @id=28,area=no,landuse=grass LINESTRING(1 1,1 2,2 2) @id=29,area=something,landuse=grass LINESTRING(1 1,1 2,2 2) @id=30,area=yes,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=41,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=43,barrier=fence,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=44,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=47,area=no,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=48,area=something,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=50,area=no,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=42,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=43,barrier=fence,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=46,area=yes MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=49,area=yes,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=51,area=something,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=52,area=yes,landuse=grass osmium-tool-1.14.0/test/export/way-tagx-empty.txt000066400000000000000000000023561420023413700220210ustar00rootroot00000000000000LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2) @id=25,area=no,barrier=fence LINESTRING(1 1,1 2,2 2) @id=26,area=something,barrier=fence LINESTRING(1 1,1 2,2 2) @id=27,area=yes,barrier=fence LINESTRING(1 1,1 2,2 2) @id=28,area=no,landuse=grass LINESTRING(1 1,1 2,2 2) @id=29,area=something,landuse=grass LINESTRING(1 1,1 2,2 2) @id=30,area=yes,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=44,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=47,area=no,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=50,area=no,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=41,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=42,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=43,barrier=fence,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=45,area=something MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=46,area=yes MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=48,area=something,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=49,area=yes,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=51,area=something,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=52,area=yes,landuse=grass osmium-tool-1.14.0/test/export/way-tagx-tagx.txt000066400000000000000000000015371420023413700216260ustar00rootroot00000000000000LINESTRING(1 1,1 2,2 2) @id=21,barrier=fence LINESTRING(1 1,1 2,2 2) @id=22,area=no LINESTRING(1 1,1 2,2 2) @id=23,area=something LINESTRING(1 1,1 2,2 2) @id=24,area=yes LINESTRING(1 1,1 2,2 2) @id=25,area=no,barrier=fence LINESTRING(1 1,1 2,2 2) @id=26,area=something,barrier=fence LINESTRING(1 1,1 2,2 2) @id=27,area=yes,barrier=fence LINESTRING(1 1,1 2,2 2) @id=28,area=no,landuse=grass LINESTRING(1 1,1 2,2 2) @id=29,area=something,landuse=grass LINESTRING(1 1,1 2,2 2) @id=30,area=yes,landuse=grass LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=44,area=no LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=47,area=no,barrier=fence LINESTRING(1 1,1 2,2 2,2 1,1 1) @id=50,area=no,landuse=grass MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=46,area=yes MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=49,area=yes,barrier=fence MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1))) @id=52,area=yes,landuse=grass osmium-tool-1.14.0/test/export/way.osm000066400000000000000000000165701420023413700177060ustar00rootroot00000000000000 osmium-tool-1.14.0/test/extract/000077500000000000000000000000001420023413700165065ustar00rootroot00000000000000osmium-tool-1.14.0/test/extract/CMakeLists.txt000066400000000000000000000062061420023413700212520ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # 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() function(check_extract_opl _name _input _output _opts) check_output(extract ${_name} "extract --generator=test -f opl extract/${_input} ${_opts}" "extract/${_output}") endfunction() #----------------------------------------------------------------------------- check_extract(clean input1.osm output-clean.osm "--clean version --clean uid") check_extract(simple input1.osm output-simple.osm "-s simple --output-header=xml_josm_upload!") check_extract(complete_ways input1.osm output-complete-ways.osm "-s complete_ways") check_extract(complete_ways_norels input1.osm output-complete-ways-norels.osm "-s complete_ways -S relations=false") 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 --output-header=xml_josm_upload=false") #----------------------------------------------------------------------------- check_extract_opl(antimeridian-east-bbox antimeridian.opl output-antimeridian-east.opl "--bbox=160,60,180,80") check_extract_opl(antimeridian-west-bbox antimeridian.opl output-antimeridian-west.opl "--bbox=-180,60,-160,80") check_extract_opl(antimeridian-east-poly antimeridian.opl output-antimeridian-east.opl "--polygon=extract/polygon-russia-east.geojson") check_extract_opl(antimeridian-west-poly antimeridian.opl output-antimeridian-west.opl "--polygon=extract/polygon-russia-west.geojson") check_extract_opl(antimeridian-both-poly antimeridian.opl output-antimeridian-both.opl "--polygon=extract/polygon-russia-all.geojson") check_extract_opl(antimeridian-reverse-poly antimeridian.opl output-antimeridian-both.opl "--polygon=extract/polygon-russia-reverse.geojson") check_extract_opl(antimeridian-alaska-east-json w42394837.osm w42394837.opl "--polygon=extract/polygon-us-alaska.geojson") check_extract_opl(antimeridian-alaska-west-json w46113981.osm w46113981.opl "--polygon=extract/polygon-us-alaska.geojson") check_extract_opl(antimeridian-alaska-east-poly w42394837.osm w42394837.opl "--polygon=extract/polygon-us-alaska.poly") check_extract_opl(antimeridian-alaska-west-poly w46113981.osm w46113981.opl "--polygon=extract/polygon-us-alaska.poly") #----------------------------------------------------------------------------- osmium-tool-1.14.0/test/extract/antimeridian.opl000066400000000000000000000015441420023413700216720ustar00rootroot00000000000000n10 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x170 y66 n11 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x180 y66 n12 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x180 y70 n13 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x170 y70 n20 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x-170 y66 n21 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x-180 y66 n22 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x-180 y70 n23 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x-170 y70 w40 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn10,n11,n12,n13,n10 w41 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn20,n21,n22,n23,n20 w42 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn11,n12 w43 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn21,n22 w50 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn10,n13,n12,n11,n10 w51 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn20,n23,n22,n21,n20 w52 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn12,n11 w53 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn22,n21 osmium-tool-1.14.0/test/extract/config.json000066400000000000000000000002171420023413700206460ustar00rootroot00000000000000{ "extracts": [ { "output": "-", "output_format": "osm", "description": "Test", "bbox": [0,0,1.5,10] } ] } osmium-tool-1.14.0/test/extract/empty-root.geojson000066400000000000000000000000031420023413700222040ustar00rootroot00000000000000{} osmium-tool-1.14.0/test/extract/empty.geojson000066400000000000000000000000001420023413700212200ustar00rootroot00000000000000osmium-tool-1.14.0/test/extract/empty.osm.opl000066400000000000000000000000001420023413700211430ustar00rootroot00000000000000osmium-tool-1.14.0/test/extract/empty.poly000066400000000000000000000000001420023413700205370ustar00rootroot00000000000000osmium-tool-1.14.0/test/extract/input1.osm000066400000000000000000000043451420023413700204540ustar00rootroot00000000000000 osmium-tool-1.14.0/test/extract/invalid-root.geojson000066400000000000000000000000051420023413700224760ustar00rootroot00000000000000null osmium-tool-1.14.0/test/extract/invalid.geojson000066400000000000000000000000071420023413700215170ustar00rootroot00000000000000FOOBAR osmium-tool-1.14.0/test/extract/missing-end-polygon.poly000066400000000000000000000000741420023413700233160ustar00rootroot00000000000000foo 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.14.0/test/extract/missing-end-ring.poly000066400000000000000000000000701420023413700225620ustar00rootroot00000000000000foo 1 10.0 10.0 19.0 10.0 19.0 19.0 10.0 19.0 10.0 10.0 osmium-tool-1.14.0/test/extract/multipolygon.osm.opl000066400000000000000000000005121420023413700225570ustar00rootroot00000000000000n10 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.14.0/test/extract/no-polygon.osm.opl000066400000000000000000000001251420023413700221160ustar00rootroot00000000000000n10 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.14.0/test/extract/one-line.poly000066400000000000000000000000041420023413700211130ustar00rootroot00000000000000foo osmium-tool-1.14.0/test/extract/output-antimeridian-both.opl000066400000000000000000000015441420023413700241620ustar00rootroot00000000000000n10 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x170 y66 n11 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x180 y66 n12 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x180 y70 n13 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x170 y70 n20 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x-170 y66 n21 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x-180 y66 n22 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x-180 y70 n23 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x-170 y70 w40 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn10,n11,n12,n13,n10 w41 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn20,n21,n22,n23,n20 w42 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn11,n12 w43 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn21,n22 w50 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn10,n13,n12,n11,n10 w51 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn20,n23,n22,n21,n20 w52 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn12,n11 w53 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn22,n21 osmium-tool-1.14.0/test/extract/output-antimeridian-east.opl000066400000000000000000000006601420023413700241600ustar00rootroot00000000000000n10 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x170 y66 n11 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x180 y66 n12 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x180 y70 n13 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x170 y70 w40 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn10,n11,n12,n13,n10 w42 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn11,n12 w50 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn10,n13,n12,n11,n10 w52 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn12,n11 osmium-tool-1.14.0/test/extract/output-antimeridian-west.opl000066400000000000000000000006641420023413700242120ustar00rootroot00000000000000n20 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x-170 y66 n21 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x-180 y66 n22 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x-180 y70 n23 v1 dV c1 t2020-01-01T00:00:00Z i0 u T x-170 y70 w41 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn20,n21,n22,n23,n20 w43 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn21,n22 w51 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn20,n23,n22,n21,n20 w53 v1 dV c1 t2020-01-01T00:00:00Z i0 u T Nn22,n21 osmium-tool-1.14.0/test/extract/output-clean.osm000066400000000000000000000025611420023413700216520ustar00rootroot00000000000000 osmium-tool-1.14.0/test/extract/output-complete-ways-norels.osm000066400000000000000000000013231420023413700246540ustar00rootroot00000000000000 osmium-tool-1.14.0/test/extract/output-complete-ways.osm000066400000000000000000000030711420023413700233560ustar00rootroot00000000000000 osmium-tool-1.14.0/test/extract/output-simple.osm000066400000000000000000000022251420023413700220560ustar00rootroot00000000000000 osmium-tool-1.14.0/test/extract/output-smart-nonmp.osm000066400000000000000000000030711420023413700230400ustar00rootroot00000000000000 osmium-tool-1.14.0/test/extract/output-smart.osm000066400000000000000000000037041420023413700217160ustar00rootroot00000000000000 osmium-tool-1.14.0/test/extract/polygon-crlf.poly000066400000000000000000000001111420023413700220170ustar00rootroot00000000000000foo 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.14.0/test/extract/polygon-one-outer.poly000066400000000000000000000001001420023413700230040ustar00rootroot00000000000000foo 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.14.0/test/extract/polygon-outer-inner.poly000066400000000000000000000001721420023413700233470ustar00rootroot00000000000000foo 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.14.0/test/extract/polygon-russia-all.geojson000066400000000000000000002350551420023413700236470ustar00rootroot00000000000000{ "type": "Feature", "properties": { "name": "polygon" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 47.45024, 41.21199 ], [ 47.55554, 41.14866 ], [ 47.63965, 41.17394 ], [ 47.77601, 41.1355 ], [ 47.90696, 41.17502 ], [ 48.1129, 41.44532 ], [ 48.41078, 41.55137 ], [ 48.62989, 41.80192 ], [ 48.86453, 41.95753 ], [ 48.60773, 42.16834 ], [ 48.23971, 42.57976 ], [ 47.97945, 42.99383 ], [ 47.84597, 43.11901 ], [ 47.88465, 43.29552 ], [ 47.85146, 43.47209 ], [ 47.89469, 43.61146 ], [ 48.16466, 43.87705 ], [ 48.19536, 43.98996 ], [ 48.1644, 44.09189 ], [ 48.04129, 44.20116 ], [ 47.8084, 44.24603 ], [ 47.89509, 44.44452 ], [ 47.78865, 44.65814 ], [ 47.59802, 44.74029 ], [ 47.37386, 44.72613 ], [ 47.64786, 45.15848 ], [ 48.05696, 45.24572 ], [ 48.27987, 45.40203 ], [ 48.67183, 45.35084 ], [ 48.86567, 45.38544 ], [ 49.01144, 45.47855 ], [ 49.11256, 45.65282 ], [ 49.93666, 46.04634 ], [ 49.71829, 46.23479 ], [ 49.52308, 46.24281 ], [ 49.19315, 46.4275 ], [ 48.62393, 46.65237 ], [ 48.92563, 46.6427 ], [ 49.04755, 46.75114 ], [ 48.56782, 47.43402 ], [ 48.46943, 47.47112 ], [ 48.23329, 47.7388 ], [ 48.04813, 47.81218 ], [ 47.66885, 47.80996 ], [ 47.41085, 47.8885 ], [ 47.35203, 47.76545 ], [ 47.23594, 47.80066 ], [ 47.22767, 47.87353 ], [ 47.14475, 47.95903 ], [ 47.26121, 48.07877 ], [ 47.17553, 48.15345 ], [ 47.15755, 48.3071 ], [ 46.59034, 48.46934 ], [ 46.80537, 48.89006 ], [ 47.0122, 48.9948 ], [ 47.09872, 49.14378 ], [ 47.0187, 49.27955 ], [ 46.85039, 49.38503 ], [ 46.94498, 49.81672 ], [ 47.19074, 49.88336 ], [ 47.38377, 50.05208 ], [ 47.36594, 50.27447 ], [ 47.51007, 50.37976 ], [ 47.59166, 50.40748 ], [ 47.89502, 50.20414 ], [ 48.05998, 50.05301 ], [ 48.20312, 49.82278 ], [ 48.4479, 49.75097 ], [ 48.76092, 49.87291 ], [ 48.95297, 50.02451 ], [ 48.77469, 50.29923 ], [ 48.71294, 50.54935 ], [ 48.83899, 50.54948 ], [ 49.14368, 50.73163 ], [ 49.45624, 50.81043 ], [ 49.49517, 50.88162 ], [ 49.43494, 51.00972 ], [ 49.46337, 51.05153 ], [ 49.77528, 51.05602 ], [ 50.02016, 51.19171 ], [ 50.38884, 51.28291 ], [ 50.43973, 51.36955 ], [ 50.59199, 51.43686 ], [ 50.62893, 51.56545 ], [ 50.76797, 51.52409 ], [ 50.84618, 51.54813 ], [ 50.87969, 51.63323 ], [ 51.23949, 51.62827 ], [ 51.19473, 51.52671 ], [ 51.26264, 51.44307 ], [ 51.58176, 51.45817 ], [ 51.63571, 51.40443 ], [ 51.85604, 51.46959 ], [ 51.84275, 51.56811 ], [ 51.90648, 51.62539 ], [ 52.09789, 51.60852 ], [ 52.31873, 51.68726 ], [ 52.54097, 51.40815 ], [ 52.78196, 51.44728 ], [ 52.94984, 51.40401 ], [ 53.22514, 51.45484 ], [ 53.53716, 51.3739 ], [ 53.55134, 51.28157 ], [ 53.63629, 51.18537 ], [ 53.99397, 51.1117 ], [ 54.08016, 51.06506 ], [ 54.17041, 50.92215 ], [ 54.42749, 50.80938 ], [ 54.36506, 50.61075 ], [ 54.54151, 50.47668 ], [ 54.64616, 50.49797 ], [ 54.78157, 50.61327 ], [ 54.72781, 50.8079 ], [ 54.74457, 50.91284 ], [ 54.65958, 50.97017 ], [ 55.02412, 50.85762 ], [ 55.02561, 50.77932 ], [ 55.36266, 50.60933 ], [ 55.47464, 50.61864 ], [ 55.71887, 50.49804 ], [ 56.08227, 50.65105 ], [ 56.17464, 50.72225 ], [ 56.2094, 50.861 ], [ 56.37383, 50.8525 ], [ 56.49571, 50.9305 ], [ 56.51267, 51.00062 ], [ 56.71622, 50.92326 ], [ 56.79957, 50.96934 ], [ 56.77757, 51.03494 ], [ 57.16343, 51.04051 ], [ 57.2991, 50.89787 ], [ 57.50648, 50.82501 ], [ 57.57432, 50.88038 ], [ 57.79196, 50.87955 ], [ 57.81701, 51.06097 ], [ 58.16644, 51.01243 ], [ 58.29841, 51.09797 ], [ 58.36807, 51.02613 ], [ 58.5548, 51.00639 ], [ 58.55671, 50.83518 ], [ 58.61717, 50.82102 ], [ 58.63651, 50.76234 ], [ 58.75108, 50.75904 ], [ 58.87397, 50.64752 ], [ 59.40752, 50.5865 ], [ 59.41208, 50.5204 ], [ 59.50366, 50.44446 ], [ 59.83658, 50.49067 ], [ 60.03802, 50.64431 ], [ 60.04013, 50.76267 ], [ 60.14419, 50.78129 ], [ 60.30811, 50.62164 ], [ 60.82497, 50.60673 ], [ 61.4775, 50.76372 ], [ 61.6091, 51.18039 ], [ 61.71087, 51.2122 ], [ 61.73371, 51.27975 ], [ 61.505, 51.45935 ], [ 61.02821, 51.52042 ], [ 60.97324, 51.56357 ], [ 60.9563, 51.66168 ], [ 60.48638, 51.69575 ], [ 60.55666, 51.7417 ], [ 60.55461, 51.83352 ], [ 60.19803, 51.9389 ], [ 60.52283, 52.10175 ], [ 60.74276, 52.11238 ], [ 61.10595, 52.3143 ], [ 61.0192, 52.54008 ], [ 60.90531, 52.56987 ], [ 60.88123, 52.67443 ], [ 60.7726, 52.69768 ], [ 61.16093, 52.94651 ], [ 61.47824, 52.97811 ], [ 61.62182, 52.90428 ], [ 61.7987, 52.94538 ], [ 62.0233, 52.89914 ], [ 62.16733, 52.95498 ], [ 62.19602, 53.05015 ], [ 62.13175, 53.16199 ], [ 61.81359, 53.22919 ], [ 61.70444, 53.30797 ], [ 61.54245, 53.26888 ], [ 61.23391, 53.34354 ], [ 61.28709, 53.45849 ], [ 61.47316, 53.4121 ], [ 61.58914, 53.45228 ], [ 61.64179, 53.52702 ], [ 61.56672, 53.64116 ], [ 61.2198, 53.61791 ], [ 61.11265, 53.6706 ], [ 61.27224, 53.77458 ], [ 61.32252, 54.02155 ], [ 61.43208, 54.02931 ], [ 61.55738, 53.92026 ], [ 61.70177, 53.96783 ], [ 61.93821, 53.8984 ], [ 62.07141, 53.90617 ], [ 62.08669, 53.99158 ], [ 62.3479, 53.98152 ], [ 62.40841, 53.89399 ], [ 62.5166, 53.86345 ], [ 62.62218, 53.93064 ], [ 62.63738, 54.02574 ], [ 63.09202, 54.05401 ], [ 63.23851, 54.14052 ], [ 63.79068, 54.21601 ], [ 63.97411, 54.14977 ], [ 64.10045, 54.25829 ], [ 64.61423, 54.32537 ], [ 64.75536, 54.3044 ], [ 64.95391, 54.36365 ], [ 65.10061, 54.28314 ], [ 65.23567, 54.28547 ], [ 65.31312, 54.35856 ], [ 65.27782, 54.4981 ], [ 65.51136, 54.51945 ], [ 65.55275, 54.58507 ], [ 65.76179, 54.55718 ], [ 65.90964, 54.65084 ], [ 66.01484, 54.57539 ], [ 67.07417, 54.73086 ], [ 67.32834, 54.81538 ], [ 67.69672, 54.81308 ], [ 67.80211, 54.84358 ], [ 67.86256, 54.92386 ], [ 68.24901, 54.92079 ], [ 68.36633, 55.06849 ], [ 68.30415, 55.13647 ], [ 68.64694, 55.15331 ], [ 68.77505, 55.31655 ], [ 69.02836, 55.23811 ], [ 69.03674, 55.37045 ], [ 69.20471, 55.28023 ], [ 69.37966, 55.32359 ], [ 69.48628, 55.28513 ], [ 69.7053, 55.29902 ], [ 69.93304, 55.16394 ], [ 70.20063, 55.09731 ], [ 70.41639, 55.16605 ], [ 70.46601, 55.22237 ], [ 70.76852, 55.23043 ], [ 70.9409, 55.05848 ], [ 70.91112, 54.87317 ], [ 70.99774, 54.74058 ], [ 71.07781, 54.65284 ], [ 71.17515, 54.64735 ], [ 71.12151, 54.5804 ], [ 71.15395, 54.37672 ], [ 70.94941, 54.34494 ], [ 70.95604, 54.24729 ], [ 71.09352, 54.08826 ], [ 71.16922, 54.04168 ], [ 71.35058, 54.12825 ], [ 71.47602, 54.04809 ], [ 71.73271, 54.05468 ], [ 71.81381, 54.12726 ], [ 71.79116, 54.19184 ], [ 71.96843, 54.17919 ], [ 72.19242, 54.0773 ], [ 72.26859, 54.18256 ], [ 72.36464, 54.00627 ], [ 72.32821, 53.92899 ], [ 72.51375, 53.85759 ], [ 72.57601, 53.91939 ], [ 72.73967, 53.92125 ], [ 72.76257, 54.02257 ], [ 72.71928, 54.07208 ], [ 72.92642, 54.04317 ], [ 73.04924, 53.93876 ], [ 73.39994, 53.89362 ], [ 73.30287, 53.81917 ], [ 73.28642, 53.72743 ], [ 73.20671, 53.69327 ], [ 73.19241, 53.55241 ], [ 73.44144, 53.385 ], [ 73.70901, 53.55462 ], [ 73.82959, 53.5285 ], [ 73.93355, 53.59363 ], [ 74.05274, 53.5143 ], [ 74.19647, 53.53673 ], [ 74.25824, 53.45297 ], [ 74.40758, 53.40888 ], [ 74.53481, 53.55444 ], [ 74.50614, 53.6269 ], [ 74.65941, 53.62507 ], [ 74.83088, 53.76654 ], [ 75.07475, 53.74859 ], [ 75.47387, 53.93347 ], [ 75.47389, 54.04444 ], [ 76.20979, 54.20822 ], [ 76.2796, 54.29552 ], [ 76.64382, 54.2847 ], [ 76.74415, 54.34325 ], [ 76.7993, 54.3135 ], [ 76.69981, 54.20269 ], [ 76.40203, 54.19956 ], [ 76.3879, 54.10426 ], [ 76.46503, 53.9997 ], [ 77.87975, 53.24298 ], [ 79.04392, 52.00902 ], [ 80.05173, 50.69358 ], [ 80.24767, 50.84853 ], [ 80.51988, 50.93412 ], [ 80.51989, 51.14206 ], [ 80.6576, 51.16136 ], [ 80.70717, 51.25352 ], [ 81.10698, 51.13065 ], [ 81.01967, 50.91674 ], [ 81.35919, 50.92006 ], [ 81.45208, 50.70372 ], [ 81.89253, 50.7463 ], [ 82.16666, 50.67976 ], [ 82.36827, 50.72346 ], [ 82.56112, 50.69488 ], [ 82.73557, 50.77502 ], [ 82.78288, 50.86773 ], [ 82.98475, 50.83348 ], [ 83.16801, 50.95285 ], [ 83.39428, 50.95179 ], [ 83.89711, 50.76756 ], [ 83.93169, 50.69045 ], [ 84.16214, 50.50008 ], [ 84.20435, 50.27332 ], [ 84.31094, 50.17701 ], [ 84.61849, 50.15736 ], [ 84.94911, 50.02382 ], [ 84.94348, 49.87841 ], [ 85.15354, 49.70814 ], [ 85.16417, 49.60616 ], [ 85.23928, 49.54103 ], [ 85.58158, 49.55187 ], [ 85.67419, 49.49991 ], [ 85.88436, 49.50714 ], [ 85.95551, 49.4376 ], [ 86.09463, 49.47158 ], [ 86.21145, 49.41643 ], [ 86.31924, 49.54148 ], [ 86.444, 49.56335 ], [ 86.58109, 49.66593 ], [ 86.54902, 49.61732 ], [ 86.5778, 49.53995 ], [ 86.77356, 49.5029 ], [ 86.79323, 49.42129 ], [ 86.99838, 49.21372 ], [ 87.23516, 49.18828 ], [ 87.24755, 49.0826 ], [ 87.42123, 49.02101 ], [ 87.71537, 49.12298 ], [ 88.00845, 49.13609 ], [ 88.21125, 49.26367 ], [ 88.23826, 49.42432 ], [ 88.59651, 49.44701 ], [ 88.8494, 49.39079 ], [ 88.92032, 49.44588 ], [ 88.9861, 49.41323 ], [ 89.15498, 49.4515 ], [ 89.25965, 49.50635 ], [ 89.27895, 49.56276 ], [ 89.37528, 49.53596 ], [ 89.75596, 49.69343 ], [ 89.7634, 49.80047 ], [ 89.69338, 49.88559 ], [ 90.00121, 49.92667 ], [ 90.07709, 49.97752 ], [ 90.07877, 50.03075 ], [ 90.29256, 50.05998 ], [ 90.52389, 50.18479 ], [ 90.70322, 50.17162 ], [ 90.77261, 50.21512 ], [ 90.78055, 50.27553 ], [ 90.92677, 50.3018 ], [ 90.97181, 50.37544 ], [ 91.4244, 50.40232 ], [ 91.5069, 50.5069 ], [ 91.67377, 50.54436 ], [ 91.70358, 50.61791 ], [ 91.80652, 50.67285 ], [ 92.08418, 50.64518 ], [ 92.27933, 50.68308 ], [ 92.36371, 50.79781 ], [ 92.43545, 50.74418 ], [ 92.54259, 50.74061 ], [ 92.55869, 50.68319 ], [ 92.63326, 50.6551 ], [ 92.77416, 50.68068 ], [ 92.81338, 50.75551 ], [ 92.96927, 50.74261 ], [ 92.92014, 50.63042 ], [ 92.99199, 50.55842 ], [ 93.11647, 50.53637 ], [ 93.44148, 50.57837 ], [ 93.70001, 50.53328 ], [ 94.23916, 50.53319 ], [ 94.29163, 50.48363 ], [ 94.34909, 50.18726 ], [ 94.45798, 50.14274 ], [ 94.60536, 49.98558 ], [ 94.9497, 49.997 ], [ 95.02491, 49.92501 ], [ 95.4031, 49.90624 ], [ 95.52948, 49.85375 ], [ 95.80041, 49.92778 ], [ 95.85203, 49.98876 ], [ 95.96315, 49.9215 ], [ 96.06126, 49.95682 ], [ 96.23183, 49.9262 ], [ 96.40952, 49.82275 ], [ 96.52829, 49.88244 ], [ 96.6104, 49.82108 ], [ 96.72672, 49.86967 ], [ 96.94036, 49.84157 ], [ 97.21371, 49.69574 ], [ 97.33491, 49.70385 ], [ 97.51801, 49.76273 ], [ 97.60912, 49.81855 ], [ 97.63576, 49.89312 ], [ 97.73767, 49.92475 ], [ 97.81343, 49.8756 ], [ 97.91491, 49.88112 ], [ 98.10534, 49.99953 ], [ 98.35058, 50.29995 ], [ 98.37164, 50.52891 ], [ 98.07766, 50.68434 ], [ 98.02749, 50.77358 ], [ 98.07692, 50.89105 ], [ 97.90421, 51.01184 ], [ 98.01436, 51.31991 ], [ 98.08842, 51.40432 ], [ 98.25657, 51.4186 ], [ 98.29632, 51.56664 ], [ 98.4043, 51.68337 ], [ 98.78829, 51.82535 ], [ 98.9223, 52.09636 ], [ 98.99962, 52.02087 ], [ 99.198, 51.97517 ], [ 99.27698, 51.90741 ], [ 99.72202, 51.85495 ], [ 99.85793, 51.71593 ], [ 100.034, 51.67827 ], [ 100.5598, 51.6847 ], [ 101.1288, 51.47283 ], [ 101.2383, 51.48023 ], [ 101.3556, 51.40426 ], [ 101.5145, 51.44502 ], [ 101.6075, 51.3934 ], [ 102.0795, 51.31954 ], [ 102.0841, 51.1035 ], [ 102.173, 50.97255 ], [ 102.1671, 50.80767 ], [ 102.2637, 50.73078 ], [ 102.2659, 50.64856 ], [ 102.4925, 50.54337 ], [ 102.6371, 50.35583 ], [ 102.9291, 50.25778 ], [ 103.2022, 50.27522 ], [ 103.2185, 50.17473 ], [ 103.2692, 50.14192 ], [ 103.4506, 50.15905 ], [ 103.7202, 50.08042 ], [ 103.8655, 50.13703 ], [ 104.1506, 50.09528 ], [ 104.4205, 50.25897 ], [ 104.816, 50.29484 ], [ 104.9176, 50.35659 ], [ 105.1356, 50.34157 ], [ 105.3358, 50.42247 ], [ 105.9772, 50.36646 ], [ 106.0687, 50.28509 ], [ 106.2522, 50.25273 ], [ 106.6131, 50.2864 ], [ 106.9572, 50.16639 ], [ 107.0553, 50.02044 ], [ 107.2216, 49.94051 ], [ 107.8674, 49.88297 ], [ 107.9188, 49.62664 ], [ 108.2573, 49.48815 ], [ 108.3194, 49.3937 ], [ 108.5228, 49.27065 ], [ 109.1851, 49.30017 ], [ 109.5601, 49.16905 ], [ 110.2016, 49.1031 ], [ 110.3939, 49.18066 ], [ 110.675, 49.11985 ], [ 110.8318, 49.13151 ], [ 111.3795, 49.30048 ], [ 111.535, 49.27253 ], [ 111.6978, 49.33232 ], [ 111.9713, 49.33214 ], [ 112.483, 49.47066 ], [ 112.8329, 49.46813 ], [ 113.0753, 49.56811 ], [ 113.2495, 49.79361 ], [ 114.3339, 50.22572 ], [ 114.8412, 50.16705 ], [ 114.9752, 50.12079 ], [ 115.2067, 49.93925 ], [ 115.5053, 49.85507 ], [ 115.7563, 49.83735 ], [ 116.2382, 49.97786 ], [ 116.5947, 49.88062 ], [ 116.6926, 49.79324 ], [ 117.0505, 49.63472 ], [ 117.8774, 49.45985 ], [ 117.9416, 49.54323 ], [ 118.1871, 49.61285 ], [ 118.6009, 49.87309 ], [ 119.0964, 49.93556 ], [ 119.321, 50.07283 ], [ 119.3992, 50.17526 ], [ 119.4274, 50.32667 ], [ 119.3728, 50.40218 ], [ 119.2828, 50.41416 ], [ 119.3404, 50.57032 ], [ 119.5266, 50.70932 ], [ 119.5779, 50.87959 ], [ 119.7974, 51.06188 ], [ 119.8679, 51.23952 ], [ 120.0398, 51.42882 ], [ 120.0956, 51.59387 ], [ 120.6829, 51.88581 ], [ 120.7452, 51.96097 ], [ 120.8298, 52.15832 ], [ 120.79, 52.28908 ], [ 120.6923, 52.34577 ], [ 120.7762, 52.52516 ], [ 120.7613, 52.57697 ], [ 120.4502, 52.69505 ], [ 120.0884, 52.63744 ], [ 120.1049, 52.73635 ], [ 120.3116, 52.82015 ], [ 120.8901, 53.23289 ], [ 121.2326, 53.22818 ], [ 122.3246, 53.44094 ], [ 122.4353, 53.39169 ], [ 122.8514, 53.40464 ], [ 123.1574, 53.45004 ], [ 123.2722, 53.50785 ], [ 123.47, 53.44685 ], [ 123.6187, 53.48627 ], [ 123.8609, 53.43111 ], [ 124.0983, 53.29736 ], [ 124.2257, 53.31909 ], [ 124.4174, 53.16787 ], [ 124.6538, 53.15172 ], [ 124.8532, 53.05015 ], [ 124.9248, 53.06199 ], [ 124.9538, 53.13363 ], [ 125.1487, 53.15071 ], [ 125.4939, 52.99904 ], [ 125.5857, 53.02373 ], [ 125.6394, 52.96569 ], [ 125.6027, 52.90062 ], [ 125.6314, 52.82388 ], [ 125.803, 52.83892 ], [ 125.9434, 52.70869 ], [ 125.9116, 52.65355 ], [ 125.9399, 52.56955 ], [ 126.1223, 52.51982 ], [ 126.1545, 52.42823 ], [ 126.2816, 52.38269 ], [ 126.2711, 52.16747 ], [ 126.4815, 52.10319 ], [ 126.3914, 52.04517 ], [ 126.4073, 51.93178 ], [ 126.6623, 51.67533 ], [ 126.621, 51.59101 ], [ 126.7484, 51.50534 ], [ 126.7256, 51.43632 ], [ 126.7847, 51.37122 ], [ 126.7585, 51.29761 ], [ 126.8431, 51.19485 ], [ 126.8733, 51.03162 ], [ 127.0839, 50.88711 ], [ 127.2297, 50.71578 ], [ 127.2978, 50.57983 ], [ 127.2364, 50.47953 ], [ 127.2909, 50.39955 ], [ 127.2872, 50.30199 ], [ 127.5453, 50.18689 ], [ 127.4377, 50.01178 ], [ 127.5004, 49.77009 ], [ 127.6156, 49.72548 ], [ 127.6583, 49.62535 ], [ 127.8411, 49.52235 ], [ 128.1806, 49.48504 ], [ 128.5465, 49.54902 ], [ 128.6881, 49.51431 ], [ 128.7491, 49.42439 ], [ 128.9727, 49.40282 ], [ 129.0795, 49.30177 ], [ 129.218, 49.34529 ], [ 129.3668, 49.30406 ], [ 129.4291, 49.38526 ], [ 129.4759, 49.37681 ], [ 129.5408, 49.24043 ], [ 129.6882, 49.24001 ], [ 129.8921, 48.99576 ], [ 130.1979, 48.82225 ], [ 130.4284, 48.85132 ], [ 130.5595, 48.8049 ], [ 130.4748, 48.59328 ], [ 130.5535, 48.54617 ], [ 130.5905, 48.4499 ], [ 130.6787, 48.43887 ], [ 130.7561, 48.30394 ], [ 130.6185, 48.14973 ], [ 130.6074, 48.07632 ], [ 130.841, 47.88329 ], [ 130.9676, 47.65113 ], [ 131.0996, 47.63207 ], [ 131.4507, 47.69047 ], [ 131.5963, 47.60511 ], [ 131.7141, 47.65205 ], [ 131.9638, 47.61171 ], [ 132.3304, 47.70502 ], [ 132.568, 47.66682 ], [ 132.644, 47.71194 ], [ 132.7325, 47.88553 ], [ 132.8258, 47.88361 ], [ 133.0785, 48.05274 ], [ 133.5531, 48.07553 ], [ 133.624, 48.14036 ], [ 133.7354, 48.14429 ], [ 133.7865, 48.20655 ], [ 134.2169, 48.33272 ], [ 134.6858, 48.35052 ], [ 134.4936, 47.98576 ], [ 134.7102, 47.72819 ], [ 134.5187, 47.52034 ], [ 134.2986, 47.48392 ], [ 134.1255, 47.3412 ], [ 134.1005, 47.24881 ], [ 134.1693, 47.15426 ], [ 134.0129, 47.00225 ], [ 133.9657, 46.69141 ], [ 133.7971, 46.49669 ], [ 133.8315, 46.29377 ], [ 133.6469, 46.18546 ], [ 133.6674, 46.0558 ], [ 133.4254, 45.87078 ], [ 133.3554, 45.6264 ], [ 133.1504, 45.54089 ], [ 133.0403, 45.29954 ], [ 133.0559, 45.14931 ], [ 132.9346, 45.08232 ], [ 132.0293, 45.29861 ], [ 131.8762, 45.39202 ], [ 131.7397, 45.27829 ], [ 131.6433, 45.25991 ], [ 131.6028, 45.12862 ], [ 131.4421, 45.02841 ], [ 131.0879, 44.98491 ], [ 130.9201, 44.88378 ], [ 130.917, 44.79406 ], [ 131.0654, 44.65677 ], [ 131.2381, 44.08007 ], [ 131.1856, 43.98994 ], [ 131.1361, 43.55799 ], [ 131.2402, 43.41428 ], [ 131.1481, 43.24203 ], [ 131.1502, 43.15951 ], [ 131.0672, 43.08742 ], [ 131.0517, 42.97433 ], [ 130.9582, 42.91953 ], [ 130.8023, 42.93109 ], [ 130.5421, 42.86199 ], [ 130.3442, 42.73033 ], [ 130.3947, 42.66008 ], [ 130.5583, 42.6077 ], [ 130.5039, 42.50742 ], [ 130.6269, 42.28052 ], [ 130.8987, 42.12396 ], [ 133.2675, 39.96882 ], [ 140.789789, 45.836458 ], [ 142.586054, 45.579449 ], [ 145.596308, 44.66475 ], [ 145.431513, 44.13886 ], [ 145.195307, 43.763164 ], [ 145.493316, 43.534612 ], [ 145.828398, 43.384093 ], [ 146.0519, 43.12595 ], [ 180, 35.61404 ], [ 180, 83.83133 ], [ 37.2795, 83.81215 ], [ 31.27848, 70.11174 ], [ 30.77568, 69.82379 ], [ 30.88567, 69.60134 ], [ 30.54062, 69.59318 ], [ 30.24028, 69.70254 ], [ 30.07925, 69.70996 ], [ 30.04604, 69.62395 ], [ 30.11237, 69.57275 ], [ 30.01001, 69.47197 ], [ 29.84288, 69.47344 ], [ 29.56539, 69.37147 ], [ 29.28577, 69.34884 ], [ 29.18916, 69.14856 ], [ 29.04647, 69.07043 ], [ 28.90818, 69.09988 ], [ 28.36758, 68.92939 ], [ 28.45581, 68.83664 ], [ 28.68857, 68.8165 ], [ 28.38412, 68.5494 ], [ 28.61946, 68.15368 ], [ 29.29281, 68.02793 ], [ 29.62745, 67.76365 ], [ 29.92133, 67.63731 ], [ 29.88819, 67.56283 ], [ 29.04771, 67.04106 ], [ 28.98188, 66.93578 ], [ 29.07125, 66.75276 ], [ 29.43544, 66.50602 ], [ 29.66187, 66.23217 ], [ 29.89118, 66.07974 ], [ 30.06695, 65.74475 ], [ 29.67942, 65.66431 ], [ 29.73666, 65.55009 ], [ 29.68779, 65.49607 ], [ 29.67485, 65.36906 ], [ 29.56924, 65.30861 ], [ 29.55285, 65.24834 ], [ 29.61512, 65.18409 ], [ 29.78282, 65.17332 ], [ 29.59119, 65.09738 ], [ 29.54934, 65.00337 ], [ 29.56488, 64.90444 ], [ 29.70682, 64.7489 ], [ 29.99222, 64.74085 ], [ 30.02651, 64.66196 ], [ 29.94633, 64.6067 ], [ 29.93739, 64.52972 ], [ 30.00522, 64.3703 ], [ 30.42164, 64.21392 ], [ 30.49199, 64.10354 ], [ 30.22901, 63.8715 ], [ 29.9702, 63.81066 ], [ 29.93021, 63.72835 ], [ 30.46048, 63.42266 ], [ 30.77099, 63.35498 ], [ 31.18489, 63.18117 ], [ 31.2423, 63.06728 ], [ 31.49568, 62.90009 ], [ 31.11931, 62.48988 ], [ 30.61954, 62.24558 ], [ 29.69859, 61.61222 ], [ 29.4718, 61.53579 ], [ 29.20748, 61.31401 ], [ 28.79581, 61.16649 ], [ 28.63369, 61.00659 ], [ 28.49232, 60.99797 ], [ 27.85071, 60.65141 ], [ 27.64466, 60.46285 ], [ 27.6426, 60.40344 ], [ 27.4862, 60.30133 ], [ 26.86507, 60.16682 ], [ 26.39009, 59.92985 ], [ 26.91914, 59.57938 ], [ 27.82954, 59.53154 ], [ 28.12685, 59.36757 ], [ 27.88014, 59.28753 ], [ 27.68803, 59.01193 ], [ 27.30915, 58.80412 ], [ 27.48362, 58.38673 ], [ 27.44354, 58.20541 ], [ 27.55825, 58.07796 ], [ 27.63487, 57.89748 ], [ 27.51724, 57.87234 ], [ 27.26678, 57.58119 ], [ 27.33297, 57.47116 ], [ 27.48984, 57.48141 ], [ 27.48489, 57.38802 ], [ 27.80667, 57.26726 ], [ 27.77309, 57.18686 ], [ 27.66903, 57.11764 ], [ 27.68045, 56.96759 ], [ 27.60984, 56.82296 ], [ 27.64703, 56.78608 ], [ 27.84829, 56.81343 ], [ 27.86174, 56.71678 ], [ 28.12917, 56.4235 ], [ 28.11273, 56.37153 ], [ 28.16811, 56.28574 ], [ 28.10297, 56.1868 ], [ 28.11991, 56.1093 ], [ 28.30397, 56.00917 ], [ 28.58389, 56.0545 ], [ 28.72857, 55.91646 ], [ 28.86271, 55.905 ], [ 29.06219, 55.97783 ], [ 29.30575, 55.93635 ], [ 29.34851, 55.92022 ], [ 29.31199, 55.74329 ], [ 29.49395, 55.65306 ], [ 29.68037, 55.7369 ], [ 29.81433, 55.73245 ], [ 29.9147, 55.80383 ], [ 30.12313, 55.78048 ], [ 30.23792, 55.81532 ], [ 30.57809, 55.69633 ], [ 30.63959, 55.59844 ], [ 30.75319, 55.54151 ], [ 30.88151, 55.57085 ], [ 30.85992, 55.41069 ], [ 30.78692, 55.36041 ], [ 30.76885, 55.28175 ], [ 30.93431, 55.09108 ], [ 30.78148, 54.97479 ], [ 30.71476, 54.77384 ], [ 30.91914, 54.69588 ], [ 30.97209, 54.6262 ], [ 31.10248, 54.61217 ], [ 31.03625, 54.49514 ], [ 31.18732, 54.41846 ], [ 31.28732, 54.20322 ], [ 31.80737, 54.02874 ], [ 31.79375, 53.94019 ], [ 31.70897, 53.84793 ], [ 31.73503, 53.7526 ], [ 31.89973, 53.72387 ], [ 32.1166, 53.76006 ], [ 32.3069, 53.70644 ], [ 32.44324, 53.5122 ], [ 32.6811, 53.40566 ], [ 32.46274, 53.34737 ], [ 32.41788, 53.2555 ], [ 32.0986, 53.12929 ], [ 31.85271, 53.16265 ], [ 31.81184, 53.22346 ], [ 31.62667, 53.28143 ], [ 31.38296, 53.25917 ], [ 31.28393, 53.09675 ], [ 31.20669, 53.06964 ], [ 31.20841, 52.98805 ], [ 31.53098, 52.75924 ], [ 31.44993, 52.69603 ], [ 31.52909, 52.56008 ], [ 31.48765, 52.46169 ], [ 31.56666, 52.37409 ], [ 31.54027, 52.29675 ], [ 31.75549, 52.06822 ], [ 31.86193, 52.05565 ], [ 31.90689, 51.99334 ], [ 32.09497, 51.98266 ], [ 32.38992, 52.09939 ], [ 32.44809, 52.27175 ], [ 32.6915, 52.19798 ], [ 32.89863, 52.19427 ], [ 33.21088, 52.32006 ], [ 33.54886, 52.25097 ], [ 33.78861, 52.31255 ], [ 34.03332, 52.12261 ], [ 34.01219, 52.07252 ], [ 34.06314, 51.96613 ], [ 34.21642, 51.84007 ], [ 34.35746, 51.79404 ], [ 34.03453, 51.68698 ], [ 34.05617, 51.62284 ], [ 34.21773, 51.50759 ], [ 34.17101, 51.42194 ], [ 34.22899, 51.34658 ], [ 34.19268, 51.23231 ], [ 34.31097, 51.18884 ], [ 34.60857, 51.19203 ], [ 34.70031, 51.12526 ], [ 35.07328, 51.16195 ], [ 35.12019, 51.04252 ], [ 35.27827, 51.00344 ], [ 35.28067, 50.92582 ], [ 35.41448, 50.73853 ], [ 35.35064, 50.67781 ], [ 35.34606, 50.55788 ], [ 35.59275, 50.31192 ], [ 35.7418, 50.3038 ], [ 35.85155, 50.374 ], [ 36.07715, 50.39531 ], [ 36.27515, 50.24484 ], [ 36.46162, 50.25969 ], [ 36.64995, 50.16646 ], [ 36.88982, 50.28679 ], [ 37.16752, 50.30649 ], [ 37.41356, 50.38116 ], [ 37.57234, 50.255 ], [ 37.61331, 50.13249 ], [ 37.73295, 50.03249 ], [ 37.88199, 49.99718 ], [ 38.01555, 49.85233 ], [ 38.19247, 49.896 ], [ 38.28829, 50.02419 ], [ 38.3358, 49.95768 ], [ 38.65124, 49.90573 ], [ 38.92585, 49.74657 ], [ 39.17134, 49.81935 ], [ 39.25245, 49.71591 ], [ 39.54762, 49.68604 ], [ 39.6294, 49.57456 ], [ 39.79514, 49.50784 ], [ 39.99489, 49.54761 ], [ 39.98036, 49.44172 ], [ 40.1341, 49.31827 ], [ 39.89786, 49.11549 ], [ 39.62763, 49.06151 ], [ 39.64642, 48.95187 ], [ 39.75439, 48.87157 ], [ 39.65966, 48.74513 ], [ 39.61548, 48.58986 ], [ 39.66738, 48.53953 ], [ 39.80232, 48.52768 ], [ 39.79789, 48.45847 ], [ 39.85571, 48.39424 ], [ 39.79521, 48.35044 ], [ 39.79541, 48.28809 ], [ 39.8875, 48.22399 ], [ 39.73231, 48.06436 ], [ 39.76046, 47.97173 ], [ 39.71582, 47.88397 ], [ 38.87402, 47.9262 ], [ 38.74584, 47.84248 ], [ 38.72452, 47.75158 ], [ 38.32055, 47.6572 ], [ 38.2375, 47.56339 ], [ 38.24691, 47.42509 ], [ 38.17056, 47.33226 ], [ 38.17948, 47.11301 ], [ 38.23594, 46.98468 ], [ 38.11227, 46.91138 ], [ 37.62322, 46.88217 ], [ 37.41553, 46.76322 ], [ 36.64303, 45.68821 ], [ 36.33254, 45.72272 ], [ 35.99696, 45.67179 ], [ 35.78323, 45.6953 ], [ 35.5479, 45.57771 ], [ 35.25239, 45.8388 ], [ 34.95522, 45.81513 ], [ 34.86024, 45.85082 ], [ 34.834, 45.94033 ], [ 34.64487, 46.03539 ], [ 34.56099, 46.04619 ], [ 34.48616, 45.99791 ], [ 34.35945, 46.10523 ], [ 33.64373, 46.28118 ], [ 33.57107, 46.24987 ], [ 33.57418, 46.17282 ], [ 33.50204, 46.05619 ], [ 32.76382, 45.87799 ], [ 32.29008, 45.63796 ], [ 32.15053, 45.4186 ], [ 32.24215, 45.18556 ], [ 32.58196, 45.06437 ], [ 32.81426, 45.08492 ], [ 33.1961, 44.89718 ], [ 33.18807, 44.79736 ], [ 33.04632, 44.63244 ], [ 33.08447, 44.45073 ], [ 33.28842, 44.28003 ], [ 33.73338, 44.13411 ], [ 34.25741, 44.18416 ], [ 34.56984, 44.35196 ], [ 34.75216, 44.53336 ], [ 35.19419, 44.54824 ], [ 35.63792, 44.77878 ], [ 35.86723, 44.74156 ], [ 36.3213, 44.7814 ], [ 36.62697, 44.88227 ], [ 36.82653, 44.86342 ], [ 36.99347, 44.80367 ], [ 37.13441, 44.60302 ], [ 37.30884, 44.50028 ], [ 37.72977, 44.41796 ], [ 38.06819, 44.20528 ], [ 38.58442, 44.07787 ], [ 39.0957, 43.73459 ], [ 39.77181, 43.19436 ], [ 39.92102, 43.18958 ], [ 40.14963, 43.51766 ], [ 40.53619, 43.46775 ], [ 40.65366, 43.50114 ], [ 40.9289, 43.37216 ], [ 41.36808, 43.30067 ], [ 41.61549, 43.17233 ], [ 42.04859, 43.13725 ], [ 42.39962, 43.19365 ], [ 42.66235, 43.08262 ], [ 42.73485, 43.1274 ], [ 42.84302, 43.12009 ], [ 43.17041, 42.88863 ], [ 43.54686, 42.81264 ], [ 43.73402, 42.71448 ], [ 43.67202, 42.66099 ], [ 43.67724, 42.59853 ], [ 43.93197, 42.50111 ], [ 44.2535, 42.58062 ], [ 44.3303, 42.66346 ], [ 44.53225, 42.64866 ], [ 44.57483, 42.69518 ], [ 44.69127, 42.69116 ], [ 44.81052, 42.56385 ], [ 44.86958, 42.58652 ], [ 44.92369, 42.69655 ], [ 45.03821, 42.64202 ], [ 45.12851, 42.6547 ], [ 45.32356, 42.47483 ], [ 45.54435, 42.4928 ], [ 45.70059, 42.42948 ], [ 45.68852, 42.34632 ], [ 45.56284, 42.25334 ], [ 45.61474, 42.14678 ], [ 45.77294, 42.05502 ], [ 45.86065, 42.05444 ], [ 45.91019, 41.98434 ], [ 46.20599, 41.9492 ], [ 46.49783, 41.83242 ], [ 46.55742, 41.75878 ], [ 46.72213, 41.77576 ], [ 46.94197, 41.60451 ], [ 46.98537, 41.51775 ], [ 47.10308, 41.50738 ], [ 47.24051, 41.28804 ], [ 47.45024, 41.21199 ] ] ], [ [ [ -180, 72.2916 ], [ -180, 72.29053 ], [ -180, 62.26134 ], [ -172.074188, 64.033556 ], [ -168.725284, 65.414875 ], [ -168.684085, 65.990095 ], [ -169.907891, 72.234092 ], [ -180, 72.2916 ] ] ], [ [ [ 22.22727, 54.33593 ], [ 22.7962, 54.35926 ], [ 22.74021, 54.44744 ], [ 22.7093, 54.45891 ], [ 22.70476, 54.50897 ], [ 22.68861, 54.53217 ], [ 22.71956, 54.56434 ], [ 22.69213, 54.58511 ], [ 22.75463, 54.63005 ], [ 22.76275, 54.65463 ], [ 22.74373, 54.66534 ], [ 22.74301, 54.68216 ], [ 22.73321, 54.68658 ], [ 22.75458, 54.7047 ], [ 22.74835, 54.72438 ], [ 22.78026, 54.74346 ], [ 22.80989, 54.7428 ], [ 22.81955, 54.75959 ], [ 22.84556, 54.76117 ], [ 22.86419, 54.77399 ], [ 22.86373, 54.78234 ], [ 22.88351, 54.78865 ], [ 22.88011, 54.80362 ], [ 22.89215, 54.81546 ], [ 22.86936, 54.84295 ], [ 22.87459, 54.8553 ], [ 22.8486, 54.869 ], [ 22.85917, 54.89211 ], [ 22.82176, 54.91769 ], [ 22.79607, 54.90969 ], [ 22.78564, 54.92998 ], [ 22.77229, 54.92998 ], [ 22.76934, 54.94047 ], [ 22.73776, 54.95228 ], [ 22.72969, 54.96771 ], [ 22.69528, 54.97819 ], [ 22.68043, 54.99268 ], [ 22.65624, 54.9868 ], [ 22.65115, 54.9726 ], [ 22.64782, 54.9875 ], [ 22.60258, 55.02726 ], [ 22.59123, 55.07575 ], [ 22.47057, 55.05064 ], [ 22.29012, 55.071 ], [ 22.1606, 55.06165 ], [ 22.13061, 55.05093 ], [ 22.11668, 55.03312 ], [ 22.07676, 55.03107 ], [ 22.0409, 55.04771 ], [ 22.04595, 55.07927 ], [ 22.03355, 55.09001 ], [ 21.99622, 55.09254 ], [ 21.96346, 55.0801 ], [ 21.92037, 55.08658 ], [ 21.85347, 55.1025 ], [ 21.81586, 55.12522 ], [ 21.72595, 55.13858 ], [ 21.71247, 55.15668 ], [ 21.65011, 55.18673 ], [ 21.56952, 55.20409 ], [ 21.50256, 55.19329 ], [ 21.45261, 55.22705 ], [ 21.43505, 55.25676 ], [ 21.38577, 55.29945 ], [ 21.27184, 55.25158 ], [ 21.09934, 55.26235 ], [ 20.95439, 55.28694 ], [ 20.65365, 55.3899 ], [ 20.39793, 55.18633 ], [ 20.20131, 55.16615 ], [ 19.9205, 55.16401 ], [ 19.82198, 55.14569 ], [ 19.72775, 55.10661 ], [ 19.63488, 55.02533 ], [ 19.58918, 54.95461 ], [ 19.57351, 54.86918 ], [ 19.58461, 54.77262 ], [ 19.50858, 54.68355 ], [ 19.40837, 54.61169 ], [ 19.64733, 54.44727 ], [ 20.33136, 54.39511 ], [ 20.58391, 54.37189 ], [ 20.63083, 54.3604 ], [ 20.74068, 54.36326 ], [ 21.26116, 54.32314 ], [ 21.37827, 54.32501 ], [ 21.44629, 54.31282 ], [ 22.22727, 54.33593 ] ] ] ] } }osmium-tool-1.14.0/test/extract/polygon-russia-east.geojson000066400000000000000000002073661420023413700240370ustar00rootroot00000000000000{ "type": "Feature", "properties": { "name": "polygon" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 47.45024, 41.21199 ], [ 47.55554, 41.14866 ], [ 47.63965, 41.17394 ], [ 47.77601, 41.1355 ], [ 47.90696, 41.17502 ], [ 48.1129, 41.44532 ], [ 48.41078, 41.55137 ], [ 48.62989, 41.80192 ], [ 48.86453, 41.95753 ], [ 48.60773, 42.16834 ], [ 48.23971, 42.57976 ], [ 47.97945, 42.99383 ], [ 47.84597, 43.11901 ], [ 47.88465, 43.29552 ], [ 47.85146, 43.47209 ], [ 47.89469, 43.61146 ], [ 48.16466, 43.87705 ], [ 48.19536, 43.98996 ], [ 48.1644, 44.09189 ], [ 48.04129, 44.20116 ], [ 47.8084, 44.24603 ], [ 47.89509, 44.44452 ], [ 47.78865, 44.65814 ], [ 47.59802, 44.74029 ], [ 47.37386, 44.72613 ], [ 47.64786, 45.15848 ], [ 48.05696, 45.24572 ], [ 48.27987, 45.40203 ], [ 48.67183, 45.35084 ], [ 48.86567, 45.38544 ], [ 49.01144, 45.47855 ], [ 49.11256, 45.65282 ], [ 49.93666, 46.04634 ], [ 49.71829, 46.23479 ], [ 49.52308, 46.24281 ], [ 49.19315, 46.4275 ], [ 48.62393, 46.65237 ], [ 48.92563, 46.6427 ], [ 49.04755, 46.75114 ], [ 48.56782, 47.43402 ], [ 48.46943, 47.47112 ], [ 48.23329, 47.7388 ], [ 48.04813, 47.81218 ], [ 47.66885, 47.80996 ], [ 47.41085, 47.8885 ], [ 47.35203, 47.76545 ], [ 47.23594, 47.80066 ], [ 47.22767, 47.87353 ], [ 47.14475, 47.95903 ], [ 47.26121, 48.07877 ], [ 47.17553, 48.15345 ], [ 47.15755, 48.3071 ], [ 46.59034, 48.46934 ], [ 46.80537, 48.89006 ], [ 47.0122, 48.9948 ], [ 47.09872, 49.14378 ], [ 47.0187, 49.27955 ], [ 46.85039, 49.38503 ], [ 46.94498, 49.81672 ], [ 47.19074, 49.88336 ], [ 47.38377, 50.05208 ], [ 47.36594, 50.27447 ], [ 47.51007, 50.37976 ], [ 47.59166, 50.40748 ], [ 47.89502, 50.20414 ], [ 48.05998, 50.05301 ], [ 48.20312, 49.82278 ], [ 48.4479, 49.75097 ], [ 48.76092, 49.87291 ], [ 48.95297, 50.02451 ], [ 48.77469, 50.29923 ], [ 48.71294, 50.54935 ], [ 48.83899, 50.54948 ], [ 49.14368, 50.73163 ], [ 49.45624, 50.81043 ], [ 49.49517, 50.88162 ], [ 49.43494, 51.00972 ], [ 49.46337, 51.05153 ], [ 49.77528, 51.05602 ], [ 50.02016, 51.19171 ], [ 50.38884, 51.28291 ], [ 50.43973, 51.36955 ], [ 50.59199, 51.43686 ], [ 50.62893, 51.56545 ], [ 50.76797, 51.52409 ], [ 50.84618, 51.54813 ], [ 50.87969, 51.63323 ], [ 51.23949, 51.62827 ], [ 51.19473, 51.52671 ], [ 51.26264, 51.44307 ], [ 51.58176, 51.45817 ], [ 51.63571, 51.40443 ], [ 51.85604, 51.46959 ], [ 51.84275, 51.56811 ], [ 51.90648, 51.62539 ], [ 52.09789, 51.60852 ], [ 52.31873, 51.68726 ], [ 52.54097, 51.40815 ], [ 52.78196, 51.44728 ], [ 52.94984, 51.40401 ], [ 53.22514, 51.45484 ], [ 53.53716, 51.3739 ], [ 53.55134, 51.28157 ], [ 53.63629, 51.18537 ], [ 53.99397, 51.1117 ], [ 54.08016, 51.06506 ], [ 54.17041, 50.92215 ], [ 54.42749, 50.80938 ], [ 54.36506, 50.61075 ], [ 54.54151, 50.47668 ], [ 54.64616, 50.49797 ], [ 54.78157, 50.61327 ], [ 54.72781, 50.8079 ], [ 54.74457, 50.91284 ], [ 54.65958, 50.97017 ], [ 55.02412, 50.85762 ], [ 55.02561, 50.77932 ], [ 55.36266, 50.60933 ], [ 55.47464, 50.61864 ], [ 55.71887, 50.49804 ], [ 56.08227, 50.65105 ], [ 56.17464, 50.72225 ], [ 56.2094, 50.861 ], [ 56.37383, 50.8525 ], [ 56.49571, 50.9305 ], [ 56.51267, 51.00062 ], [ 56.71622, 50.92326 ], [ 56.79957, 50.96934 ], [ 56.77757, 51.03494 ], [ 57.16343, 51.04051 ], [ 57.2991, 50.89787 ], [ 57.50648, 50.82501 ], [ 57.57432, 50.88038 ], [ 57.79196, 50.87955 ], [ 57.81701, 51.06097 ], [ 58.16644, 51.01243 ], [ 58.29841, 51.09797 ], [ 58.36807, 51.02613 ], [ 58.5548, 51.00639 ], [ 58.55671, 50.83518 ], [ 58.61717, 50.82102 ], [ 58.63651, 50.76234 ], [ 58.75108, 50.75904 ], [ 58.87397, 50.64752 ], [ 59.40752, 50.5865 ], [ 59.41208, 50.5204 ], [ 59.50366, 50.44446 ], [ 59.83658, 50.49067 ], [ 60.03802, 50.64431 ], [ 60.04013, 50.76267 ], [ 60.14419, 50.78129 ], [ 60.30811, 50.62164 ], [ 60.82497, 50.60673 ], [ 61.4775, 50.76372 ], [ 61.6091, 51.18039 ], [ 61.71087, 51.2122 ], [ 61.73371, 51.27975 ], [ 61.505, 51.45935 ], [ 61.02821, 51.52042 ], [ 60.97324, 51.56357 ], [ 60.9563, 51.66168 ], [ 60.48638, 51.69575 ], [ 60.55666, 51.7417 ], [ 60.55461, 51.83352 ], [ 60.19803, 51.9389 ], [ 60.52283, 52.10175 ], [ 60.74276, 52.11238 ], [ 61.10595, 52.3143 ], [ 61.0192, 52.54008 ], [ 60.90531, 52.56987 ], [ 60.88123, 52.67443 ], [ 60.7726, 52.69768 ], [ 61.16093, 52.94651 ], [ 61.47824, 52.97811 ], [ 61.62182, 52.90428 ], [ 61.7987, 52.94538 ], [ 62.0233, 52.89914 ], [ 62.16733, 52.95498 ], [ 62.19602, 53.05015 ], [ 62.13175, 53.16199 ], [ 61.81359, 53.22919 ], [ 61.70444, 53.30797 ], [ 61.54245, 53.26888 ], [ 61.23391, 53.34354 ], [ 61.28709, 53.45849 ], [ 61.47316, 53.4121 ], [ 61.58914, 53.45228 ], [ 61.64179, 53.52702 ], [ 61.56672, 53.64116 ], [ 61.2198, 53.61791 ], [ 61.11265, 53.6706 ], [ 61.27224, 53.77458 ], [ 61.32252, 54.02155 ], [ 61.43208, 54.02931 ], [ 61.55738, 53.92026 ], [ 61.70177, 53.96783 ], [ 61.93821, 53.8984 ], [ 62.07141, 53.90617 ], [ 62.08669, 53.99158 ], [ 62.3479, 53.98152 ], [ 62.40841, 53.89399 ], [ 62.5166, 53.86345 ], [ 62.62218, 53.93064 ], [ 62.63738, 54.02574 ], [ 63.09202, 54.05401 ], [ 63.23851, 54.14052 ], [ 63.79068, 54.21601 ], [ 63.97411, 54.14977 ], [ 64.10045, 54.25829 ], [ 64.61423, 54.32537 ], [ 64.75536, 54.3044 ], [ 64.95391, 54.36365 ], [ 65.10061, 54.28314 ], [ 65.23567, 54.28547 ], [ 65.31312, 54.35856 ], [ 65.27782, 54.4981 ], [ 65.51136, 54.51945 ], [ 65.55275, 54.58507 ], [ 65.76179, 54.55718 ], [ 65.90964, 54.65084 ], [ 66.01484, 54.57539 ], [ 67.07417, 54.73086 ], [ 67.32834, 54.81538 ], [ 67.69672, 54.81308 ], [ 67.80211, 54.84358 ], [ 67.86256, 54.92386 ], [ 68.24901, 54.92079 ], [ 68.36633, 55.06849 ], [ 68.30415, 55.13647 ], [ 68.64694, 55.15331 ], [ 68.77505, 55.31655 ], [ 69.02836, 55.23811 ], [ 69.03674, 55.37045 ], [ 69.20471, 55.28023 ], [ 69.37966, 55.32359 ], [ 69.48628, 55.28513 ], [ 69.7053, 55.29902 ], [ 69.93304, 55.16394 ], [ 70.20063, 55.09731 ], [ 70.41639, 55.16605 ], [ 70.46601, 55.22237 ], [ 70.76852, 55.23043 ], [ 70.9409, 55.05848 ], [ 70.91112, 54.87317 ], [ 70.99774, 54.74058 ], [ 71.07781, 54.65284 ], [ 71.17515, 54.64735 ], [ 71.12151, 54.5804 ], [ 71.15395, 54.37672 ], [ 70.94941, 54.34494 ], [ 70.95604, 54.24729 ], [ 71.09352, 54.08826 ], [ 71.16922, 54.04168 ], [ 71.35058, 54.12825 ], [ 71.47602, 54.04809 ], [ 71.73271, 54.05468 ], [ 71.81381, 54.12726 ], [ 71.79116, 54.19184 ], [ 71.96843, 54.17919 ], [ 72.19242, 54.0773 ], [ 72.26859, 54.18256 ], [ 72.36464, 54.00627 ], [ 72.32821, 53.92899 ], [ 72.51375, 53.85759 ], [ 72.57601, 53.91939 ], [ 72.73967, 53.92125 ], [ 72.76257, 54.02257 ], [ 72.71928, 54.07208 ], [ 72.92642, 54.04317 ], [ 73.04924, 53.93876 ], [ 73.39994, 53.89362 ], [ 73.30287, 53.81917 ], [ 73.28642, 53.72743 ], [ 73.20671, 53.69327 ], [ 73.19241, 53.55241 ], [ 73.44144, 53.385 ], [ 73.70901, 53.55462 ], [ 73.82959, 53.5285 ], [ 73.93355, 53.59363 ], [ 74.05274, 53.5143 ], [ 74.19647, 53.53673 ], [ 74.25824, 53.45297 ], [ 74.40758, 53.40888 ], [ 74.53481, 53.55444 ], [ 74.50614, 53.6269 ], [ 74.65941, 53.62507 ], [ 74.83088, 53.76654 ], [ 75.07475, 53.74859 ], [ 75.47387, 53.93347 ], [ 75.47389, 54.04444 ], [ 76.20979, 54.20822 ], [ 76.2796, 54.29552 ], [ 76.64382, 54.2847 ], [ 76.74415, 54.34325 ], [ 76.7993, 54.3135 ], [ 76.69981, 54.20269 ], [ 76.40203, 54.19956 ], [ 76.3879, 54.10426 ], [ 76.46503, 53.9997 ], [ 77.87975, 53.24298 ], [ 79.04392, 52.00902 ], [ 80.05173, 50.69358 ], [ 80.24767, 50.84853 ], [ 80.51988, 50.93412 ], [ 80.51989, 51.14206 ], [ 80.6576, 51.16136 ], [ 80.70717, 51.25352 ], [ 81.10698, 51.13065 ], [ 81.01967, 50.91674 ], [ 81.35919, 50.92006 ], [ 81.45208, 50.70372 ], [ 81.89253, 50.7463 ], [ 82.16666, 50.67976 ], [ 82.36827, 50.72346 ], [ 82.56112, 50.69488 ], [ 82.73557, 50.77502 ], [ 82.78288, 50.86773 ], [ 82.98475, 50.83348 ], [ 83.16801, 50.95285 ], [ 83.39428, 50.95179 ], [ 83.89711, 50.76756 ], [ 83.93169, 50.69045 ], [ 84.16214, 50.50008 ], [ 84.20435, 50.27332 ], [ 84.31094, 50.17701 ], [ 84.61849, 50.15736 ], [ 84.94911, 50.02382 ], [ 84.94348, 49.87841 ], [ 85.15354, 49.70814 ], [ 85.16417, 49.60616 ], [ 85.23928, 49.54103 ], [ 85.58158, 49.55187 ], [ 85.67419, 49.49991 ], [ 85.88436, 49.50714 ], [ 85.95551, 49.4376 ], [ 86.09463, 49.47158 ], [ 86.21145, 49.41643 ], [ 86.31924, 49.54148 ], [ 86.444, 49.56335 ], [ 86.58109, 49.66593 ], [ 86.54902, 49.61732 ], [ 86.5778, 49.53995 ], [ 86.77356, 49.5029 ], [ 86.79323, 49.42129 ], [ 86.99838, 49.21372 ], [ 87.23516, 49.18828 ], [ 87.24755, 49.0826 ], [ 87.42123, 49.02101 ], [ 87.71537, 49.12298 ], [ 88.00845, 49.13609 ], [ 88.21125, 49.26367 ], [ 88.23826, 49.42432 ], [ 88.59651, 49.44701 ], [ 88.8494, 49.39079 ], [ 88.92032, 49.44588 ], [ 88.9861, 49.41323 ], [ 89.15498, 49.4515 ], [ 89.25965, 49.50635 ], [ 89.27895, 49.56276 ], [ 89.37528, 49.53596 ], [ 89.75596, 49.69343 ], [ 89.7634, 49.80047 ], [ 89.69338, 49.88559 ], [ 90.00121, 49.92667 ], [ 90.07709, 49.97752 ], [ 90.07877, 50.03075 ], [ 90.29256, 50.05998 ], [ 90.52389, 50.18479 ], [ 90.70322, 50.17162 ], [ 90.77261, 50.21512 ], [ 90.78055, 50.27553 ], [ 90.92677, 50.3018 ], [ 90.97181, 50.37544 ], [ 91.4244, 50.40232 ], [ 91.5069, 50.5069 ], [ 91.67377, 50.54436 ], [ 91.70358, 50.61791 ], [ 91.80652, 50.67285 ], [ 92.08418, 50.64518 ], [ 92.27933, 50.68308 ], [ 92.36371, 50.79781 ], [ 92.43545, 50.74418 ], [ 92.54259, 50.74061 ], [ 92.55869, 50.68319 ], [ 92.63326, 50.6551 ], [ 92.77416, 50.68068 ], [ 92.81338, 50.75551 ], [ 92.96927, 50.74261 ], [ 92.92014, 50.63042 ], [ 92.99199, 50.55842 ], [ 93.11647, 50.53637 ], [ 93.44148, 50.57837 ], [ 93.70001, 50.53328 ], [ 94.23916, 50.53319 ], [ 94.29163, 50.48363 ], [ 94.34909, 50.18726 ], [ 94.45798, 50.14274 ], [ 94.60536, 49.98558 ], [ 94.9497, 49.997 ], [ 95.02491, 49.92501 ], [ 95.4031, 49.90624 ], [ 95.52948, 49.85375 ], [ 95.80041, 49.92778 ], [ 95.85203, 49.98876 ], [ 95.96315, 49.9215 ], [ 96.06126, 49.95682 ], [ 96.23183, 49.9262 ], [ 96.40952, 49.82275 ], [ 96.52829, 49.88244 ], [ 96.6104, 49.82108 ], [ 96.72672, 49.86967 ], [ 96.94036, 49.84157 ], [ 97.21371, 49.69574 ], [ 97.33491, 49.70385 ], [ 97.51801, 49.76273 ], [ 97.60912, 49.81855 ], [ 97.63576, 49.89312 ], [ 97.73767, 49.92475 ], [ 97.81343, 49.8756 ], [ 97.91491, 49.88112 ], [ 98.10534, 49.99953 ], [ 98.35058, 50.29995 ], [ 98.37164, 50.52891 ], [ 98.07766, 50.68434 ], [ 98.02749, 50.77358 ], [ 98.07692, 50.89105 ], [ 97.90421, 51.01184 ], [ 98.01436, 51.31991 ], [ 98.08842, 51.40432 ], [ 98.25657, 51.4186 ], [ 98.29632, 51.56664 ], [ 98.4043, 51.68337 ], [ 98.78829, 51.82535 ], [ 98.9223, 52.09636 ], [ 98.99962, 52.02087 ], [ 99.198, 51.97517 ], [ 99.27698, 51.90741 ], [ 99.72202, 51.85495 ], [ 99.85793, 51.71593 ], [ 100.034, 51.67827 ], [ 100.5598, 51.6847 ], [ 101.1288, 51.47283 ], [ 101.2383, 51.48023 ], [ 101.3556, 51.40426 ], [ 101.5145, 51.44502 ], [ 101.6075, 51.3934 ], [ 102.0795, 51.31954 ], [ 102.0841, 51.1035 ], [ 102.173, 50.97255 ], [ 102.1671, 50.80767 ], [ 102.2637, 50.73078 ], [ 102.2659, 50.64856 ], [ 102.4925, 50.54337 ], [ 102.6371, 50.35583 ], [ 102.9291, 50.25778 ], [ 103.2022, 50.27522 ], [ 103.2185, 50.17473 ], [ 103.2692, 50.14192 ], [ 103.4506, 50.15905 ], [ 103.7202, 50.08042 ], [ 103.8655, 50.13703 ], [ 104.1506, 50.09528 ], [ 104.4205, 50.25897 ], [ 104.816, 50.29484 ], [ 104.9176, 50.35659 ], [ 105.1356, 50.34157 ], [ 105.3358, 50.42247 ], [ 105.9772, 50.36646 ], [ 106.0687, 50.28509 ], [ 106.2522, 50.25273 ], [ 106.6131, 50.2864 ], [ 106.9572, 50.16639 ], [ 107.0553, 50.02044 ], [ 107.2216, 49.94051 ], [ 107.8674, 49.88297 ], [ 107.9188, 49.62664 ], [ 108.2573, 49.48815 ], [ 108.3194, 49.3937 ], [ 108.5228, 49.27065 ], [ 109.1851, 49.30017 ], [ 109.5601, 49.16905 ], [ 110.2016, 49.1031 ], [ 110.3939, 49.18066 ], [ 110.675, 49.11985 ], [ 110.8318, 49.13151 ], [ 111.3795, 49.30048 ], [ 111.535, 49.27253 ], [ 111.6978, 49.33232 ], [ 111.9713, 49.33214 ], [ 112.483, 49.47066 ], [ 112.8329, 49.46813 ], [ 113.0753, 49.56811 ], [ 113.2495, 49.79361 ], [ 114.3339, 50.22572 ], [ 114.8412, 50.16705 ], [ 114.9752, 50.12079 ], [ 115.2067, 49.93925 ], [ 115.5053, 49.85507 ], [ 115.7563, 49.83735 ], [ 116.2382, 49.97786 ], [ 116.5947, 49.88062 ], [ 116.6926, 49.79324 ], [ 117.0505, 49.63472 ], [ 117.8774, 49.45985 ], [ 117.9416, 49.54323 ], [ 118.1871, 49.61285 ], [ 118.6009, 49.87309 ], [ 119.0964, 49.93556 ], [ 119.321, 50.07283 ], [ 119.3992, 50.17526 ], [ 119.4274, 50.32667 ], [ 119.3728, 50.40218 ], [ 119.2828, 50.41416 ], [ 119.3404, 50.57032 ], [ 119.5266, 50.70932 ], [ 119.5779, 50.87959 ], [ 119.7974, 51.06188 ], [ 119.8679, 51.23952 ], [ 120.0398, 51.42882 ], [ 120.0956, 51.59387 ], [ 120.6829, 51.88581 ], [ 120.7452, 51.96097 ], [ 120.8298, 52.15832 ], [ 120.79, 52.28908 ], [ 120.6923, 52.34577 ], [ 120.7762, 52.52516 ], [ 120.7613, 52.57697 ], [ 120.4502, 52.69505 ], [ 120.0884, 52.63744 ], [ 120.1049, 52.73635 ], [ 120.3116, 52.82015 ], [ 120.8901, 53.23289 ], [ 121.2326, 53.22818 ], [ 122.3246, 53.44094 ], [ 122.4353, 53.39169 ], [ 122.8514, 53.40464 ], [ 123.1574, 53.45004 ], [ 123.2722, 53.50785 ], [ 123.47, 53.44685 ], [ 123.6187, 53.48627 ], [ 123.8609, 53.43111 ], [ 124.0983, 53.29736 ], [ 124.2257, 53.31909 ], [ 124.4174, 53.16787 ], [ 124.6538, 53.15172 ], [ 124.8532, 53.05015 ], [ 124.9248, 53.06199 ], [ 124.9538, 53.13363 ], [ 125.1487, 53.15071 ], [ 125.4939, 52.99904 ], [ 125.5857, 53.02373 ], [ 125.6394, 52.96569 ], [ 125.6027, 52.90062 ], [ 125.6314, 52.82388 ], [ 125.803, 52.83892 ], [ 125.9434, 52.70869 ], [ 125.9116, 52.65355 ], [ 125.9399, 52.56955 ], [ 126.1223, 52.51982 ], [ 126.1545, 52.42823 ], [ 126.2816, 52.38269 ], [ 126.2711, 52.16747 ], [ 126.4815, 52.10319 ], [ 126.3914, 52.04517 ], [ 126.4073, 51.93178 ], [ 126.6623, 51.67533 ], [ 126.621, 51.59101 ], [ 126.7484, 51.50534 ], [ 126.7256, 51.43632 ], [ 126.7847, 51.37122 ], [ 126.7585, 51.29761 ], [ 126.8431, 51.19485 ], [ 126.8733, 51.03162 ], [ 127.0839, 50.88711 ], [ 127.2297, 50.71578 ], [ 127.2978, 50.57983 ], [ 127.2364, 50.47953 ], [ 127.2909, 50.39955 ], [ 127.2872, 50.30199 ], [ 127.5453, 50.18689 ], [ 127.4377, 50.01178 ], [ 127.5004, 49.77009 ], [ 127.6156, 49.72548 ], [ 127.6583, 49.62535 ], [ 127.8411, 49.52235 ], [ 128.1806, 49.48504 ], [ 128.5465, 49.54902 ], [ 128.6881, 49.51431 ], [ 128.7491, 49.42439 ], [ 128.9727, 49.40282 ], [ 129.0795, 49.30177 ], [ 129.218, 49.34529 ], [ 129.3668, 49.30406 ], [ 129.4291, 49.38526 ], [ 129.4759, 49.37681 ], [ 129.5408, 49.24043 ], [ 129.6882, 49.24001 ], [ 129.8921, 48.99576 ], [ 130.1979, 48.82225 ], [ 130.4284, 48.85132 ], [ 130.5595, 48.8049 ], [ 130.4748, 48.59328 ], [ 130.5535, 48.54617 ], [ 130.5905, 48.4499 ], [ 130.6787, 48.43887 ], [ 130.7561, 48.30394 ], [ 130.6185, 48.14973 ], [ 130.6074, 48.07632 ], [ 130.841, 47.88329 ], [ 130.9676, 47.65113 ], [ 131.0996, 47.63207 ], [ 131.4507, 47.69047 ], [ 131.5963, 47.60511 ], [ 131.7141, 47.65205 ], [ 131.9638, 47.61171 ], [ 132.3304, 47.70502 ], [ 132.568, 47.66682 ], [ 132.644, 47.71194 ], [ 132.7325, 47.88553 ], [ 132.8258, 47.88361 ], [ 133.0785, 48.05274 ], [ 133.5531, 48.07553 ], [ 133.624, 48.14036 ], [ 133.7354, 48.14429 ], [ 133.7865, 48.20655 ], [ 134.2169, 48.33272 ], [ 134.6858, 48.35052 ], [ 134.4936, 47.98576 ], [ 134.7102, 47.72819 ], [ 134.5187, 47.52034 ], [ 134.2986, 47.48392 ], [ 134.1255, 47.3412 ], [ 134.1005, 47.24881 ], [ 134.1693, 47.15426 ], [ 134.0129, 47.00225 ], [ 133.9657, 46.69141 ], [ 133.7971, 46.49669 ], [ 133.8315, 46.29377 ], [ 133.6469, 46.18546 ], [ 133.6674, 46.0558 ], [ 133.4254, 45.87078 ], [ 133.3554, 45.6264 ], [ 133.1504, 45.54089 ], [ 133.0403, 45.29954 ], [ 133.0559, 45.14931 ], [ 132.9346, 45.08232 ], [ 132.0293, 45.29861 ], [ 131.8762, 45.39202 ], [ 131.7397, 45.27829 ], [ 131.6433, 45.25991 ], [ 131.6028, 45.12862 ], [ 131.4421, 45.02841 ], [ 131.0879, 44.98491 ], [ 130.9201, 44.88378 ], [ 130.917, 44.79406 ], [ 131.0654, 44.65677 ], [ 131.2381, 44.08007 ], [ 131.1856, 43.98994 ], [ 131.1361, 43.55799 ], [ 131.2402, 43.41428 ], [ 131.1481, 43.24203 ], [ 131.1502, 43.15951 ], [ 131.0672, 43.08742 ], [ 131.0517, 42.97433 ], [ 130.9582, 42.91953 ], [ 130.8023, 42.93109 ], [ 130.5421, 42.86199 ], [ 130.3442, 42.73033 ], [ 130.3947, 42.66008 ], [ 130.5583, 42.6077 ], [ 130.5039, 42.50742 ], [ 130.6269, 42.28052 ], [ 130.8987, 42.12396 ], [ 133.2675, 39.96882 ], [ 140.789789, 45.836458 ], [ 142.586054, 45.579449 ], [ 145.596308, 44.66475 ], [ 145.431513, 44.13886 ], [ 145.195307, 43.763164 ], [ 145.493316, 43.534612 ], [ 145.828398, 43.384093 ], [ 146.0519, 43.12595 ], [ 180, 35.61404 ], [ 180, 83.83133 ], [ 37.2795, 83.81215 ], [ 31.27848, 70.11174 ], [ 30.77568, 69.82379 ], [ 30.88567, 69.60134 ], [ 30.54062, 69.59318 ], [ 30.24028, 69.70254 ], [ 30.07925, 69.70996 ], [ 30.04604, 69.62395 ], [ 30.11237, 69.57275 ], [ 30.01001, 69.47197 ], [ 29.84288, 69.47344 ], [ 29.56539, 69.37147 ], [ 29.28577, 69.34884 ], [ 29.18916, 69.14856 ], [ 29.04647, 69.07043 ], [ 28.90818, 69.09988 ], [ 28.36758, 68.92939 ], [ 28.45581, 68.83664 ], [ 28.68857, 68.8165 ], [ 28.38412, 68.5494 ], [ 28.61946, 68.15368 ], [ 29.29281, 68.02793 ], [ 29.62745, 67.76365 ], [ 29.92133, 67.63731 ], [ 29.88819, 67.56283 ], [ 29.04771, 67.04106 ], [ 28.98188, 66.93578 ], [ 29.07125, 66.75276 ], [ 29.43544, 66.50602 ], [ 29.66187, 66.23217 ], [ 29.89118, 66.07974 ], [ 30.06695, 65.74475 ], [ 29.67942, 65.66431 ], [ 29.73666, 65.55009 ], [ 29.68779, 65.49607 ], [ 29.67485, 65.36906 ], [ 29.56924, 65.30861 ], [ 29.55285, 65.24834 ], [ 29.61512, 65.18409 ], [ 29.78282, 65.17332 ], [ 29.59119, 65.09738 ], [ 29.54934, 65.00337 ], [ 29.56488, 64.90444 ], [ 29.70682, 64.7489 ], [ 29.99222, 64.74085 ], [ 30.02651, 64.66196 ], [ 29.94633, 64.6067 ], [ 29.93739, 64.52972 ], [ 30.00522, 64.3703 ], [ 30.42164, 64.21392 ], [ 30.49199, 64.10354 ], [ 30.22901, 63.8715 ], [ 29.9702, 63.81066 ], [ 29.93021, 63.72835 ], [ 30.46048, 63.42266 ], [ 30.77099, 63.35498 ], [ 31.18489, 63.18117 ], [ 31.2423, 63.06728 ], [ 31.49568, 62.90009 ], [ 31.11931, 62.48988 ], [ 30.61954, 62.24558 ], [ 29.69859, 61.61222 ], [ 29.4718, 61.53579 ], [ 29.20748, 61.31401 ], [ 28.79581, 61.16649 ], [ 28.63369, 61.00659 ], [ 28.49232, 60.99797 ], [ 27.85071, 60.65141 ], [ 27.64466, 60.46285 ], [ 27.6426, 60.40344 ], [ 27.4862, 60.30133 ], [ 26.86507, 60.16682 ], [ 26.39009, 59.92985 ], [ 26.91914, 59.57938 ], [ 27.82954, 59.53154 ], [ 28.12685, 59.36757 ], [ 27.88014, 59.28753 ], [ 27.68803, 59.01193 ], [ 27.30915, 58.80412 ], [ 27.48362, 58.38673 ], [ 27.44354, 58.20541 ], [ 27.55825, 58.07796 ], [ 27.63487, 57.89748 ], [ 27.51724, 57.87234 ], [ 27.26678, 57.58119 ], [ 27.33297, 57.47116 ], [ 27.48984, 57.48141 ], [ 27.48489, 57.38802 ], [ 27.80667, 57.26726 ], [ 27.77309, 57.18686 ], [ 27.66903, 57.11764 ], [ 27.68045, 56.96759 ], [ 27.60984, 56.82296 ], [ 27.64703, 56.78608 ], [ 27.84829, 56.81343 ], [ 27.86174, 56.71678 ], [ 28.12917, 56.4235 ], [ 28.11273, 56.37153 ], [ 28.16811, 56.28574 ], [ 28.10297, 56.1868 ], [ 28.11991, 56.1093 ], [ 28.30397, 56.00917 ], [ 28.58389, 56.0545 ], [ 28.72857, 55.91646 ], [ 28.86271, 55.905 ], [ 29.06219, 55.97783 ], [ 29.30575, 55.93635 ], [ 29.34851, 55.92022 ], [ 29.31199, 55.74329 ], [ 29.49395, 55.65306 ], [ 29.68037, 55.7369 ], [ 29.81433, 55.73245 ], [ 29.9147, 55.80383 ], [ 30.12313, 55.78048 ], [ 30.23792, 55.81532 ], [ 30.57809, 55.69633 ], [ 30.63959, 55.59844 ], [ 30.75319, 55.54151 ], [ 30.88151, 55.57085 ], [ 30.85992, 55.41069 ], [ 30.78692, 55.36041 ], [ 30.76885, 55.28175 ], [ 30.93431, 55.09108 ], [ 30.78148, 54.97479 ], [ 30.71476, 54.77384 ], [ 30.91914, 54.69588 ], [ 30.97209, 54.6262 ], [ 31.10248, 54.61217 ], [ 31.03625, 54.49514 ], [ 31.18732, 54.41846 ], [ 31.28732, 54.20322 ], [ 31.80737, 54.02874 ], [ 31.79375, 53.94019 ], [ 31.70897, 53.84793 ], [ 31.73503, 53.7526 ], [ 31.89973, 53.72387 ], [ 32.1166, 53.76006 ], [ 32.3069, 53.70644 ], [ 32.44324, 53.5122 ], [ 32.6811, 53.40566 ], [ 32.46274, 53.34737 ], [ 32.41788, 53.2555 ], [ 32.0986, 53.12929 ], [ 31.85271, 53.16265 ], [ 31.81184, 53.22346 ], [ 31.62667, 53.28143 ], [ 31.38296, 53.25917 ], [ 31.28393, 53.09675 ], [ 31.20669, 53.06964 ], [ 31.20841, 52.98805 ], [ 31.53098, 52.75924 ], [ 31.44993, 52.69603 ], [ 31.52909, 52.56008 ], [ 31.48765, 52.46169 ], [ 31.56666, 52.37409 ], [ 31.54027, 52.29675 ], [ 31.75549, 52.06822 ], [ 31.86193, 52.05565 ], [ 31.90689, 51.99334 ], [ 32.09497, 51.98266 ], [ 32.38992, 52.09939 ], [ 32.44809, 52.27175 ], [ 32.6915, 52.19798 ], [ 32.89863, 52.19427 ], [ 33.21088, 52.32006 ], [ 33.54886, 52.25097 ], [ 33.78861, 52.31255 ], [ 34.03332, 52.12261 ], [ 34.01219, 52.07252 ], [ 34.06314, 51.96613 ], [ 34.21642, 51.84007 ], [ 34.35746, 51.79404 ], [ 34.03453, 51.68698 ], [ 34.05617, 51.62284 ], [ 34.21773, 51.50759 ], [ 34.17101, 51.42194 ], [ 34.22899, 51.34658 ], [ 34.19268, 51.23231 ], [ 34.31097, 51.18884 ], [ 34.60857, 51.19203 ], [ 34.70031, 51.12526 ], [ 35.07328, 51.16195 ], [ 35.12019, 51.04252 ], [ 35.27827, 51.00344 ], [ 35.28067, 50.92582 ], [ 35.41448, 50.73853 ], [ 35.35064, 50.67781 ], [ 35.34606, 50.55788 ], [ 35.59275, 50.31192 ], [ 35.7418, 50.3038 ], [ 35.85155, 50.374 ], [ 36.07715, 50.39531 ], [ 36.27515, 50.24484 ], [ 36.46162, 50.25969 ], [ 36.64995, 50.16646 ], [ 36.88982, 50.28679 ], [ 37.16752, 50.30649 ], [ 37.41356, 50.38116 ], [ 37.57234, 50.255 ], [ 37.61331, 50.13249 ], [ 37.73295, 50.03249 ], [ 37.88199, 49.99718 ], [ 38.01555, 49.85233 ], [ 38.19247, 49.896 ], [ 38.28829, 50.02419 ], [ 38.3358, 49.95768 ], [ 38.65124, 49.90573 ], [ 38.92585, 49.74657 ], [ 39.17134, 49.81935 ], [ 39.25245, 49.71591 ], [ 39.54762, 49.68604 ], [ 39.6294, 49.57456 ], [ 39.79514, 49.50784 ], [ 39.99489, 49.54761 ], [ 39.98036, 49.44172 ], [ 40.1341, 49.31827 ], [ 39.89786, 49.11549 ], [ 39.62763, 49.06151 ], [ 39.64642, 48.95187 ], [ 39.75439, 48.87157 ], [ 39.65966, 48.74513 ], [ 39.61548, 48.58986 ], [ 39.66738, 48.53953 ], [ 39.80232, 48.52768 ], [ 39.79789, 48.45847 ], [ 39.85571, 48.39424 ], [ 39.79521, 48.35044 ], [ 39.79541, 48.28809 ], [ 39.8875, 48.22399 ], [ 39.73231, 48.06436 ], [ 39.76046, 47.97173 ], [ 39.71582, 47.88397 ], [ 38.87402, 47.9262 ], [ 38.74584, 47.84248 ], [ 38.72452, 47.75158 ], [ 38.32055, 47.6572 ], [ 38.2375, 47.56339 ], [ 38.24691, 47.42509 ], [ 38.17056, 47.33226 ], [ 38.17948, 47.11301 ], [ 38.23594, 46.98468 ], [ 38.11227, 46.91138 ], [ 37.62322, 46.88217 ], [ 37.41553, 46.76322 ], [ 36.64303, 45.68821 ], [ 36.33254, 45.72272 ], [ 35.99696, 45.67179 ], [ 35.78323, 45.6953 ], [ 35.5479, 45.57771 ], [ 35.25239, 45.8388 ], [ 34.95522, 45.81513 ], [ 34.86024, 45.85082 ], [ 34.834, 45.94033 ], [ 34.64487, 46.03539 ], [ 34.56099, 46.04619 ], [ 34.48616, 45.99791 ], [ 34.35945, 46.10523 ], [ 33.64373, 46.28118 ], [ 33.57107, 46.24987 ], [ 33.57418, 46.17282 ], [ 33.50204, 46.05619 ], [ 32.76382, 45.87799 ], [ 32.29008, 45.63796 ], [ 32.15053, 45.4186 ], [ 32.24215, 45.18556 ], [ 32.58196, 45.06437 ], [ 32.81426, 45.08492 ], [ 33.1961, 44.89718 ], [ 33.18807, 44.79736 ], [ 33.04632, 44.63244 ], [ 33.08447, 44.45073 ], [ 33.28842, 44.28003 ], [ 33.73338, 44.13411 ], [ 34.25741, 44.18416 ], [ 34.56984, 44.35196 ], [ 34.75216, 44.53336 ], [ 35.19419, 44.54824 ], [ 35.63792, 44.77878 ], [ 35.86723, 44.74156 ], [ 36.3213, 44.7814 ], [ 36.62697, 44.88227 ], [ 36.82653, 44.86342 ], [ 36.99347, 44.80367 ], [ 37.13441, 44.60302 ], [ 37.30884, 44.50028 ], [ 37.72977, 44.41796 ], [ 38.06819, 44.20528 ], [ 38.58442, 44.07787 ], [ 39.0957, 43.73459 ], [ 39.77181, 43.19436 ], [ 39.92102, 43.18958 ], [ 40.14963, 43.51766 ], [ 40.53619, 43.46775 ], [ 40.65366, 43.50114 ], [ 40.9289, 43.37216 ], [ 41.36808, 43.30067 ], [ 41.61549, 43.17233 ], [ 42.04859, 43.13725 ], [ 42.39962, 43.19365 ], [ 42.66235, 43.08262 ], [ 42.73485, 43.1274 ], [ 42.84302, 43.12009 ], [ 43.17041, 42.88863 ], [ 43.54686, 42.81264 ], [ 43.73402, 42.71448 ], [ 43.67202, 42.66099 ], [ 43.67724, 42.59853 ], [ 43.93197, 42.50111 ], [ 44.2535, 42.58062 ], [ 44.3303, 42.66346 ], [ 44.53225, 42.64866 ], [ 44.57483, 42.69518 ], [ 44.69127, 42.69116 ], [ 44.81052, 42.56385 ], [ 44.86958, 42.58652 ], [ 44.92369, 42.69655 ], [ 45.03821, 42.64202 ], [ 45.12851, 42.6547 ], [ 45.32356, 42.47483 ], [ 45.54435, 42.4928 ], [ 45.70059, 42.42948 ], [ 45.68852, 42.34632 ], [ 45.56284, 42.25334 ], [ 45.61474, 42.14678 ], [ 45.77294, 42.05502 ], [ 45.86065, 42.05444 ], [ 45.91019, 41.98434 ], [ 46.20599, 41.9492 ], [ 46.49783, 41.83242 ], [ 46.55742, 41.75878 ], [ 46.72213, 41.77576 ], [ 46.94197, 41.60451 ], [ 46.98537, 41.51775 ], [ 47.10308, 41.50738 ], [ 47.24051, 41.28804 ], [ 47.45024, 41.21199 ] ] ] ] } } osmium-tool-1.14.0/test/extract/polygon-russia-reverse.geojson000066400000000000000000000644171420023413700245540ustar00rootroot00000000000000{ "type": "FeatureCollection", "name": "russia", "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, "features": [ { "type": "Feature", "properties": { "name": "polygon" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 47.45024, 41.21199 ], [ 47.24051, 41.28804 ], [ 47.10308, 41.50738 ], [ 46.98537, 41.51775 ], [ 46.94197, 41.60451 ], [ 46.72213, 41.77576 ], [ 46.55742, 41.75878 ], [ 46.49783, 41.83242 ], [ 46.20599, 41.9492 ], [ 45.91019, 41.98434 ], [ 45.86065, 42.05444 ], [ 45.77294, 42.05502 ], [ 45.61474, 42.14678 ], [ 45.56284, 42.25334 ], [ 45.68852, 42.34632 ], [ 45.70059, 42.42948 ], [ 45.54435, 42.4928 ], [ 45.32356, 42.47483 ], [ 45.12851, 42.6547 ], [ 45.03821, 42.64202 ], [ 44.92369, 42.69655 ], [ 44.86958, 42.58652 ], [ 44.81052, 42.56385 ], [ 44.69127, 42.69116 ], [ 44.57483, 42.69518 ], [ 44.53225, 42.64866 ], [ 44.3303, 42.66346 ], [ 44.2535, 42.58062 ], [ 43.93197, 42.50111 ], [ 43.67724, 42.59853 ], [ 43.67202, 42.66099 ], [ 43.73402, 42.71448 ], [ 43.54686, 42.81264 ], [ 43.17041, 42.88863 ], [ 42.84302, 43.12009 ], [ 42.73485, 43.1274 ], [ 42.66235, 43.08262 ], [ 42.39962, 43.19365 ], [ 42.04859, 43.13725 ], [ 41.61549, 43.17233 ], [ 41.36808, 43.30067 ], [ 40.9289, 43.37216 ], [ 40.65366, 43.50114 ], [ 40.53619, 43.46775 ], [ 40.14963, 43.51766 ], [ 39.92102, 43.18958 ], [ 39.77181, 43.19436 ], [ 39.0957, 43.73459 ], [ 38.58442, 44.07787 ], [ 38.06819, 44.20528 ], [ 37.72977, 44.41796 ], [ 37.30884, 44.50028 ], [ 37.13441, 44.60302 ], [ 36.99347, 44.80367 ], [ 36.82653, 44.86342 ], [ 36.62697, 44.88227 ], [ 36.3213, 44.7814 ], [ 35.86723, 44.74156 ], [ 35.63792, 44.77878 ], [ 35.19419, 44.54824 ], [ 34.75216, 44.53336 ], [ 34.56984, 44.35196 ], [ 34.25741, 44.18416 ], [ 33.73338, 44.13411 ], [ 33.28842, 44.28003 ], [ 33.08447, 44.45073 ], [ 33.04632, 44.63244 ], [ 33.18807, 44.79736 ], [ 33.1961, 44.89718 ], [ 32.81426, 45.08492 ], [ 32.58196, 45.06437 ], [ 32.24215, 45.18556 ], [ 32.15053, 45.4186 ], [ 32.29008, 45.63796 ], [ 32.76382, 45.87799 ], [ 33.50204, 46.05619 ], [ 33.57418, 46.17282 ], [ 33.57107, 46.24987 ], [ 33.64373, 46.28118 ], [ 34.35945, 46.10523 ], [ 34.48616, 45.99791 ], [ 34.56099, 46.04619 ], [ 34.64487, 46.03539 ], [ 34.834, 45.94033 ], [ 34.86024, 45.85082 ], [ 34.95522, 45.81513 ], [ 35.25239, 45.8388 ], [ 35.5479, 45.57771 ], [ 35.78323, 45.6953 ], [ 35.99696, 45.67179 ], [ 36.33254, 45.72272 ], [ 36.64303, 45.68821 ], [ 37.41553, 46.76322 ], [ 37.62322, 46.88217 ], [ 38.11227, 46.91138 ], [ 38.23594, 46.98468 ], [ 38.17948, 47.11301 ], [ 38.17056, 47.33226 ], [ 38.24691, 47.42509 ], [ 38.2375, 47.56339 ], [ 38.32055, 47.6572 ], [ 38.72452, 47.75158 ], [ 38.74584, 47.84248 ], [ 38.87402, 47.9262 ], [ 39.71582, 47.88397 ], [ 39.76046, 47.97173 ], [ 39.73231, 48.06436 ], [ 39.8875, 48.22399 ], [ 39.79541, 48.28809 ], [ 39.79521, 48.35044 ], [ 39.85571, 48.39424 ], [ 39.79789, 48.45847 ], [ 39.80232, 48.52768 ], [ 39.66738, 48.53953 ], [ 39.61548, 48.58986 ], [ 39.65966, 48.74513 ], [ 39.75439, 48.87157 ], [ 39.64642, 48.95187 ], [ 39.62763, 49.06151 ], [ 39.89786, 49.11549 ], [ 40.1341, 49.31827 ], [ 39.98036, 49.44172 ], [ 39.99489, 49.54761 ], [ 39.79514, 49.50784 ], [ 39.6294, 49.57456 ], [ 39.54762, 49.68604 ], [ 39.25245, 49.71591 ], [ 39.17134, 49.81935 ], [ 38.92585, 49.74657 ], [ 38.65124, 49.90573 ], [ 38.3358, 49.95768 ], [ 38.28829, 50.02419 ], [ 38.19247, 49.896 ], [ 38.01555, 49.85233 ], [ 37.88199, 49.99718 ], [ 37.73295, 50.03249 ], [ 37.61331, 50.13249 ], [ 37.57234, 50.255 ], [ 37.41356, 50.38116 ], [ 37.16752, 50.30649 ], [ 36.88982, 50.28679 ], [ 36.64995, 50.16646 ], [ 36.46162, 50.25969 ], [ 36.27515, 50.24484 ], [ 36.07715, 50.39531 ], [ 35.85155, 50.374 ], [ 35.7418, 50.3038 ], [ 35.59275, 50.31192 ], [ 35.34606, 50.55788 ], [ 35.35064, 50.67781 ], [ 35.41448, 50.73853 ], [ 35.28067, 50.92582 ], [ 35.27827, 51.00344 ], [ 35.12019, 51.04252 ], [ 35.07328, 51.16195 ], [ 34.70031, 51.12526 ], [ 34.60857, 51.19203 ], [ 34.31097, 51.18884 ], [ 34.19268, 51.23231 ], [ 34.22899, 51.34658 ], [ 34.17101, 51.42194 ], [ 34.21773, 51.50759 ], [ 34.05617, 51.62284 ], [ 34.03453, 51.68698 ], [ 34.35746, 51.79404 ], [ 34.21642, 51.84007 ], [ 34.06314, 51.96613 ], [ 34.01219, 52.07252 ], [ 34.03332, 52.12261 ], [ 33.78861, 52.31255 ], [ 33.54886, 52.25097 ], [ 33.21088, 52.32006 ], [ 32.89863, 52.19427 ], [ 32.6915, 52.19798 ], [ 32.44809, 52.27175 ], [ 32.38992, 52.09939 ], [ 32.09497, 51.98266 ], [ 31.90689, 51.99334 ], [ 31.86193, 52.05565 ], [ 31.75549, 52.06822 ], [ 31.54027, 52.29675 ], [ 31.56666, 52.37409 ], [ 31.48765, 52.46169 ], [ 31.52909, 52.56008 ], [ 31.44993, 52.69603 ], [ 31.53098, 52.75924 ], [ 31.20841, 52.98805 ], [ 31.20669, 53.06964 ], [ 31.28393, 53.09675 ], [ 31.38296, 53.25917 ], [ 31.62667, 53.28143 ], [ 31.81184, 53.22346 ], [ 31.85271, 53.16265 ], [ 32.0986, 53.12929 ], [ 32.41788, 53.2555 ], [ 32.46274, 53.34737 ], [ 32.6811, 53.40566 ], [ 32.44324, 53.5122 ], [ 32.3069, 53.70644 ], [ 32.1166, 53.76006 ], [ 31.89973, 53.72387 ], [ 31.73503, 53.7526 ], [ 31.70897, 53.84793 ], [ 31.79375, 53.94019 ], [ 31.80737, 54.02874 ], [ 31.28732, 54.20322 ], [ 31.18732, 54.41846 ], [ 31.03625, 54.49514 ], [ 31.10248, 54.61217 ], [ 30.97209, 54.6262 ], [ 30.91914, 54.69588 ], [ 30.71476, 54.77384 ], [ 30.78148, 54.97479 ], [ 30.93431, 55.09108 ], [ 30.76885, 55.28175 ], [ 30.78692, 55.36041 ], [ 30.85992, 55.41069 ], [ 30.88151, 55.57085 ], [ 30.75319, 55.54151 ], [ 30.63959, 55.59844 ], [ 30.57809, 55.69633 ], [ 30.23792, 55.81532 ], [ 30.12313, 55.78048 ], [ 29.9147, 55.80383 ], [ 29.81433, 55.73245 ], [ 29.68037, 55.7369 ], [ 29.49395, 55.65306 ], [ 29.31199, 55.74329 ], [ 29.34851, 55.92022 ], [ 29.30575, 55.93635 ], [ 29.06219, 55.97783 ], [ 28.86271, 55.905 ], [ 28.72857, 55.91646 ], [ 28.58389, 56.0545 ], [ 28.30397, 56.00917 ], [ 28.11991, 56.1093 ], [ 28.10297, 56.1868 ], [ 28.16811, 56.28574 ], [ 28.11273, 56.37153 ], [ 28.12917, 56.4235 ], [ 27.86174, 56.71678 ], [ 27.84829, 56.81343 ], [ 27.64703, 56.78608 ], [ 27.60984, 56.82296 ], [ 27.68045, 56.96759 ], [ 27.66903, 57.11764 ], [ 27.77309, 57.18686 ], [ 27.80667, 57.26726 ], [ 27.48489, 57.38802 ], [ 27.48984, 57.48141 ], [ 27.33297, 57.47116 ], [ 27.26678, 57.58119 ], [ 27.51724, 57.87234 ], [ 27.63487, 57.89748 ], [ 27.55825, 58.07796 ], [ 27.44354, 58.20541 ], [ 27.48362, 58.38673 ], [ 27.30915, 58.80412 ], [ 27.68803, 59.01193 ], [ 27.88014, 59.28753 ], [ 28.12685, 59.36757 ], [ 27.82954, 59.53154 ], [ 26.91914, 59.57938 ], [ 26.39009, 59.92985 ], [ 26.86507, 60.16682 ], [ 27.4862, 60.30133 ], [ 27.6426, 60.40344 ], [ 27.64466, 60.46285 ], [ 27.85071, 60.65141 ], [ 28.49232, 60.99797 ], [ 28.63369, 61.00659 ], [ 28.79581, 61.16649 ], [ 29.20748, 61.31401 ], [ 29.4718, 61.53579 ], [ 29.69859, 61.61222 ], [ 30.61954, 62.24558 ], [ 31.11931, 62.48988 ], [ 31.49568, 62.90009 ], [ 31.2423, 63.06728 ], [ 31.18489, 63.18117 ], [ 30.77099, 63.35498 ], [ 30.46048, 63.42266 ], [ 29.93021, 63.72835 ], [ 29.9702, 63.81066 ], [ 30.22901, 63.8715 ], [ 30.49199, 64.10354 ], [ 30.42164, 64.21392 ], [ 30.00522, 64.3703 ], [ 29.93739, 64.52972 ], [ 29.94633, 64.6067 ], [ 30.02651, 64.66196 ], [ 29.99222, 64.74085 ], [ 29.70682, 64.7489 ], [ 29.56488, 64.90444 ], [ 29.54934, 65.00337 ], [ 29.59119, 65.09738 ], [ 29.78282, 65.17332 ], [ 29.61512, 65.18409 ], [ 29.55285, 65.24834 ], [ 29.56924, 65.30861 ], [ 29.67485, 65.36906 ], [ 29.68779, 65.49607 ], [ 29.73666, 65.55009 ], [ 29.67942, 65.66431 ], [ 30.06695, 65.74475 ], [ 29.89118, 66.07974 ], [ 29.66187, 66.23217 ], [ 29.43544, 66.50602 ], [ 29.07125, 66.75276 ], [ 28.98188, 66.93578 ], [ 29.04771, 67.04106 ], [ 29.88819, 67.56283 ], [ 29.92133, 67.63731 ], [ 29.62745, 67.76365 ], [ 29.29281, 68.02793 ], [ 28.61946, 68.15368 ], [ 28.38412, 68.5494 ], [ 28.68857, 68.8165 ], [ 28.45581, 68.83664 ], [ 28.36758, 68.92939 ], [ 28.90818, 69.09988 ], [ 29.04647, 69.07043 ], [ 29.18916, 69.14856 ], [ 29.28577, 69.34884 ], [ 29.56539, 69.37147 ], [ 29.84288, 69.47344 ], [ 30.01001, 69.47197 ], [ 30.11237, 69.57275 ], [ 30.04604, 69.62395 ], [ 30.07925, 69.70996 ], [ 30.24028, 69.70254 ], [ 30.54062, 69.59318 ], [ 30.88567, 69.60134 ], [ 30.77568, 69.82379 ], [ 31.27848, 70.11174 ], [ 37.2795, 83.81215 ], [ 180.0, 83.83133 ], [ 180.0, 35.61404 ], [ 146.0519, 43.12595 ], [ 145.828398, 43.384093 ], [ 145.493316, 43.534612 ], [ 145.195307, 43.763164 ], [ 145.431513, 44.13886 ], [ 145.596308, 44.66475 ], [ 142.586054, 45.579449 ], [ 140.789789, 45.836458 ], [ 133.2675, 39.96882 ], [ 130.8987, 42.12396 ], [ 130.6269, 42.28052 ], [ 130.5039, 42.50742 ], [ 130.5583, 42.6077 ], [ 130.3947, 42.66008 ], [ 130.3442, 42.73033 ], [ 130.5421, 42.86199 ], [ 130.8023, 42.93109 ], [ 130.9582, 42.91953 ], [ 131.0517, 42.97433 ], [ 131.0672, 43.08742 ], [ 131.1502, 43.15951 ], [ 131.1481, 43.24203 ], [ 131.2402, 43.41428 ], [ 131.1361, 43.55799 ], [ 131.1856, 43.98994 ], [ 131.2381, 44.08007 ], [ 131.0654, 44.65677 ], [ 130.917, 44.79406 ], [ 130.9201, 44.88378 ], [ 131.0879, 44.98491 ], [ 131.4421, 45.02841 ], [ 131.6028, 45.12862 ], [ 131.6433, 45.25991 ], [ 131.7397, 45.27829 ], [ 131.8762, 45.39202 ], [ 132.0293, 45.29861 ], [ 132.9346, 45.08232 ], [ 133.0559, 45.14931 ], [ 133.0403, 45.29954 ], [ 133.1504, 45.54089 ], [ 133.3554, 45.6264 ], [ 133.4254, 45.87078 ], [ 133.6674, 46.0558 ], [ 133.6469, 46.18546 ], [ 133.8315, 46.29377 ], [ 133.7971, 46.49669 ], [ 133.9657, 46.69141 ], [ 134.0129, 47.00225 ], [ 134.1693, 47.15426 ], [ 134.1005, 47.24881 ], [ 134.1255, 47.3412 ], [ 134.2986, 47.48392 ], [ 134.5187, 47.52034 ], [ 134.7102, 47.72819 ], [ 134.4936, 47.98576 ], [ 134.6858, 48.35052 ], [ 134.2169, 48.33272 ], [ 133.7865, 48.20655 ], [ 133.7354, 48.14429 ], [ 133.624, 48.14036 ], [ 133.5531, 48.07553 ], [ 133.0785, 48.05274 ], [ 132.8258, 47.88361 ], [ 132.7325, 47.88553 ], [ 132.644, 47.71194 ], [ 132.568, 47.66682 ], [ 132.3304, 47.70502 ], [ 131.9638, 47.61171 ], [ 131.7141, 47.65205 ], [ 131.5963, 47.60511 ], [ 131.4507, 47.69047 ], [ 131.0996, 47.63207 ], [ 130.9676, 47.65113 ], [ 130.841, 47.88329 ], [ 130.6074, 48.07632 ], [ 130.6185, 48.14973 ], [ 130.7561, 48.30394 ], [ 130.6787, 48.43887 ], [ 130.5905, 48.4499 ], [ 130.5535, 48.54617 ], [ 130.4748, 48.59328 ], [ 130.5595, 48.8049 ], [ 130.4284, 48.85132 ], [ 130.1979, 48.82225 ], [ 129.8921, 48.99576 ], [ 129.6882, 49.24001 ], [ 129.5408, 49.24043 ], [ 129.4759, 49.37681 ], [ 129.4291, 49.38526 ], [ 129.3668, 49.30406 ], [ 129.218, 49.34529 ], [ 129.0795, 49.30177 ], [ 128.9727, 49.40282 ], [ 128.7491, 49.42439 ], [ 128.6881, 49.51431 ], [ 128.5465, 49.54902 ], [ 128.1806, 49.48504 ], [ 127.8411, 49.52235 ], [ 127.6583, 49.62535 ], [ 127.6156, 49.72548 ], [ 127.5004, 49.77009 ], [ 127.4377, 50.01178 ], [ 127.5453, 50.18689 ], [ 127.2872, 50.30199 ], [ 127.2909, 50.39955 ], [ 127.2364, 50.47953 ], [ 127.2978, 50.57983 ], [ 127.2297, 50.71578 ], [ 127.0839, 50.88711 ], [ 126.8733, 51.03162 ], [ 126.8431, 51.19485 ], [ 126.7585, 51.29761 ], [ 126.7847, 51.37122 ], [ 126.7256, 51.43632 ], [ 126.7484, 51.50534 ], [ 126.621, 51.59101 ], [ 126.6623, 51.67533 ], [ 126.4073, 51.93178 ], [ 126.3914, 52.04517 ], [ 126.4815, 52.10319 ], [ 126.2711, 52.16747 ], [ 126.2816, 52.38269 ], [ 126.1545, 52.42823 ], [ 126.1223, 52.51982 ], [ 125.9399, 52.56955 ], [ 125.9116, 52.65355 ], [ 125.9434, 52.70869 ], [ 125.803, 52.83892 ], [ 125.6314, 52.82388 ], [ 125.6027, 52.90062 ], [ 125.6394, 52.96569 ], [ 125.5857, 53.02373 ], [ 125.4939, 52.99904 ], [ 125.1487, 53.15071 ], [ 124.9538, 53.13363 ], [ 124.9248, 53.06199 ], [ 124.8532, 53.05015 ], [ 124.6538, 53.15172 ], [ 124.4174, 53.16787 ], [ 124.2257, 53.31909 ], [ 124.0983, 53.29736 ], [ 123.8609, 53.43111 ], [ 123.6187, 53.48627 ], [ 123.47, 53.44685 ], [ 123.2722, 53.50785 ], [ 123.1574, 53.45004 ], [ 122.8514, 53.40464 ], [ 122.4353, 53.39169 ], [ 122.3246, 53.44094 ], [ 121.2326, 53.22818 ], [ 120.8901, 53.23289 ], [ 120.3116, 52.82015 ], [ 120.1049, 52.73635 ], [ 120.0884, 52.63744 ], [ 120.4502, 52.69505 ], [ 120.7613, 52.57697 ], [ 120.7762, 52.52516 ], [ 120.6923, 52.34577 ], [ 120.79, 52.28908 ], [ 120.8298, 52.15832 ], [ 120.7452, 51.96097 ], [ 120.6829, 51.88581 ], [ 120.0956, 51.59387 ], [ 120.0398, 51.42882 ], [ 119.8679, 51.23952 ], [ 119.7974, 51.06188 ], [ 119.5779, 50.87959 ], [ 119.5266, 50.70932 ], [ 119.3404, 50.57032 ], [ 119.2828, 50.41416 ], [ 119.3728, 50.40218 ], [ 119.4274, 50.32667 ], [ 119.3992, 50.17526 ], [ 119.321, 50.07283 ], [ 119.0964, 49.93556 ], [ 118.6009, 49.87309 ], [ 118.1871, 49.61285 ], [ 117.9416, 49.54323 ], [ 117.8774, 49.45985 ], [ 117.0505, 49.63472 ], [ 116.6926, 49.79324 ], [ 116.5947, 49.88062 ], [ 116.2382, 49.97786 ], [ 115.7563, 49.83735 ], [ 115.5053, 49.85507 ], [ 115.2067, 49.93925 ], [ 114.9752, 50.12079 ], [ 114.8412, 50.16705 ], [ 114.3339, 50.22572 ], [ 113.2495, 49.79361 ], [ 113.0753, 49.56811 ], [ 112.8329, 49.46813 ], [ 112.483, 49.47066 ], [ 111.9713, 49.33214 ], [ 111.6978, 49.33232 ], [ 111.535, 49.27253 ], [ 111.3795, 49.30048 ], [ 110.8318, 49.13151 ], [ 110.675, 49.11985 ], [ 110.3939, 49.18066 ], [ 110.2016, 49.1031 ], [ 109.5601, 49.16905 ], [ 109.1851, 49.30017 ], [ 108.5228, 49.27065 ], [ 108.3194, 49.3937 ], [ 108.2573, 49.48815 ], [ 107.9188, 49.62664 ], [ 107.8674, 49.88297 ], [ 107.2216, 49.94051 ], [ 107.0553, 50.02044 ], [ 106.9572, 50.16639 ], [ 106.6131, 50.2864 ], [ 106.2522, 50.25273 ], [ 106.0687, 50.28509 ], [ 105.9772, 50.36646 ], [ 105.3358, 50.42247 ], [ 105.1356, 50.34157 ], [ 104.9176, 50.35659 ], [ 104.816, 50.29484 ], [ 104.4205, 50.25897 ], [ 104.1506, 50.09528 ], [ 103.8655, 50.13703 ], [ 103.7202, 50.08042 ], [ 103.4506, 50.15905 ], [ 103.2692, 50.14192 ], [ 103.2185, 50.17473 ], [ 103.2022, 50.27522 ], [ 102.9291, 50.25778 ], [ 102.6371, 50.35583 ], [ 102.4925, 50.54337 ], [ 102.2659, 50.64856 ], [ 102.2637, 50.73078 ], [ 102.1671, 50.80767 ], [ 102.173, 50.97255 ], [ 102.0841, 51.1035 ], [ 102.0795, 51.31954 ], [ 101.6075, 51.3934 ], [ 101.5145, 51.44502 ], [ 101.3556, 51.40426 ], [ 101.2383, 51.48023 ], [ 101.1288, 51.47283 ], [ 100.5598, 51.6847 ], [ 100.034, 51.67827 ], [ 99.85793, 51.71593 ], [ 99.72202, 51.85495 ], [ 99.27698, 51.90741 ], [ 99.198, 51.97517 ], [ 98.99962, 52.02087 ], [ 98.9223, 52.09636 ], [ 98.78829, 51.82535 ], [ 98.4043, 51.68337 ], [ 98.29632, 51.56664 ], [ 98.25657, 51.4186 ], [ 98.08842, 51.40432 ], [ 98.01436, 51.31991 ], [ 97.90421, 51.01184 ], [ 98.07692, 50.89105 ], [ 98.02749, 50.77358 ], [ 98.07766, 50.68434 ], [ 98.37164, 50.52891 ], [ 98.35058, 50.29995 ], [ 98.10534, 49.99953 ], [ 97.91491, 49.88112 ], [ 97.81343, 49.8756 ], [ 97.73767, 49.92475 ], [ 97.63576, 49.89312 ], [ 97.60912, 49.81855 ], [ 97.51801, 49.76273 ], [ 97.33491, 49.70385 ], [ 97.21371, 49.69574 ], [ 96.94036, 49.84157 ], [ 96.72672, 49.86967 ], [ 96.6104, 49.82108 ], [ 96.52829, 49.88244 ], [ 96.40952, 49.82275 ], [ 96.23183, 49.9262 ], [ 96.06126, 49.95682 ], [ 95.96315, 49.9215 ], [ 95.85203, 49.98876 ], [ 95.80041, 49.92778 ], [ 95.52948, 49.85375 ], [ 95.4031, 49.90624 ], [ 95.02491, 49.92501 ], [ 94.9497, 49.997 ], [ 94.60536, 49.98558 ], [ 94.45798, 50.14274 ], [ 94.34909, 50.18726 ], [ 94.29163, 50.48363 ], [ 94.23916, 50.53319 ], [ 93.70001, 50.53328 ], [ 93.44148, 50.57837 ], [ 93.11647, 50.53637 ], [ 92.99199, 50.55842 ], [ 92.92014, 50.63042 ], [ 92.96927, 50.74261 ], [ 92.81338, 50.75551 ], [ 92.77416, 50.68068 ], [ 92.63326, 50.6551 ], [ 92.55869, 50.68319 ], [ 92.54259, 50.74061 ], [ 92.43545, 50.74418 ], [ 92.36371, 50.79781 ], [ 92.27933, 50.68308 ], [ 92.08418, 50.64518 ], [ 91.80652, 50.67285 ], [ 91.70358, 50.61791 ], [ 91.67377, 50.54436 ], [ 91.5069, 50.5069 ], [ 91.4244, 50.40232 ], [ 90.97181, 50.37544 ], [ 90.92677, 50.3018 ], [ 90.78055, 50.27553 ], [ 90.77261, 50.21512 ], [ 90.70322, 50.17162 ], [ 90.52389, 50.18479 ], [ 90.29256, 50.05998 ], [ 90.07877, 50.03075 ], [ 90.07709, 49.97752 ], [ 90.00121, 49.92667 ], [ 89.69338, 49.88559 ], [ 89.7634, 49.80047 ], [ 89.75596, 49.69343 ], [ 89.37528, 49.53596 ], [ 89.27895, 49.56276 ], [ 89.25965, 49.50635 ], [ 89.15498, 49.4515 ], [ 88.9861, 49.41323 ], [ 88.92032, 49.44588 ], [ 88.8494, 49.39079 ], [ 88.59651, 49.44701 ], [ 88.23826, 49.42432 ], [ 88.21125, 49.26367 ], [ 88.00845, 49.13609 ], [ 87.71537, 49.12298 ], [ 87.42123, 49.02101 ], [ 87.24755, 49.0826 ], [ 87.23516, 49.18828 ], [ 86.99838, 49.21372 ], [ 86.79323, 49.42129 ], [ 86.77356, 49.5029 ], [ 86.5778, 49.53995 ], [ 86.54902, 49.61732 ], [ 86.58109, 49.66593 ], [ 86.444, 49.56335 ], [ 86.31924, 49.54148 ], [ 86.21145, 49.41643 ], [ 86.09463, 49.47158 ], [ 85.95551, 49.4376 ], [ 85.88436, 49.50714 ], [ 85.67419, 49.49991 ], [ 85.58158, 49.55187 ], [ 85.23928, 49.54103 ], [ 85.16417, 49.60616 ], [ 85.15354, 49.70814 ], [ 84.94348, 49.87841 ], [ 84.94911, 50.02382 ], [ 84.61849, 50.15736 ], [ 84.31094, 50.17701 ], [ 84.20435, 50.27332 ], [ 84.16214, 50.50008 ], [ 83.93169, 50.69045 ], [ 83.89711, 50.76756 ], [ 83.39428, 50.95179 ], [ 83.16801, 50.95285 ], [ 82.98475, 50.83348 ], [ 82.78288, 50.86773 ], [ 82.73557, 50.77502 ], [ 82.56112, 50.69488 ], [ 82.36827, 50.72346 ], [ 82.16666, 50.67976 ], [ 81.89253, 50.7463 ], [ 81.45208, 50.70372 ], [ 81.35919, 50.92006 ], [ 81.01967, 50.91674 ], [ 81.10698, 51.13065 ], [ 80.70717, 51.25352 ], [ 80.6576, 51.16136 ], [ 80.51989, 51.14206 ], [ 80.51988, 50.93412 ], [ 80.24767, 50.84853 ], [ 80.05173, 50.69358 ], [ 79.04392, 52.00902 ], [ 77.87975, 53.24298 ], [ 76.46503, 53.9997 ], [ 76.3879, 54.10426 ], [ 76.40203, 54.19956 ], [ 76.69981, 54.20269 ], [ 76.7993, 54.3135 ], [ 76.74415, 54.34325 ], [ 76.64382, 54.2847 ], [ 76.2796, 54.29552 ], [ 76.20979, 54.20822 ], [ 75.47389, 54.04444 ], [ 75.47387, 53.93347 ], [ 75.07475, 53.74859 ], [ 74.83088, 53.76654 ], [ 74.65941, 53.62507 ], [ 74.50614, 53.6269 ], [ 74.53481, 53.55444 ], [ 74.40758, 53.40888 ], [ 74.25824, 53.45297 ], [ 74.19647, 53.53673 ], [ 74.05274, 53.5143 ], [ 73.93355, 53.59363 ], [ 73.82959, 53.5285 ], [ 73.70901, 53.55462 ], [ 73.44144, 53.385 ], [ 73.19241, 53.55241 ], [ 73.20671, 53.69327 ], [ 73.28642, 53.72743 ], [ 73.30287, 53.81917 ], [ 73.39994, 53.89362 ], [ 73.04924, 53.93876 ], [ 72.92642, 54.04317 ], [ 72.71928, 54.07208 ], [ 72.76257, 54.02257 ], [ 72.73967, 53.92125 ], [ 72.57601, 53.91939 ], [ 72.51375, 53.85759 ], [ 72.32821, 53.92899 ], [ 72.36464, 54.00627 ], [ 72.26859, 54.18256 ], [ 72.19242, 54.0773 ], [ 71.96843, 54.17919 ], [ 71.79116, 54.19184 ], [ 71.81381, 54.12726 ], [ 71.73271, 54.05468 ], [ 71.47602, 54.04809 ], [ 71.35058, 54.12825 ], [ 71.16922, 54.04168 ], [ 71.09352, 54.08826 ], [ 70.95604, 54.24729 ], [ 70.94941, 54.34494 ], [ 71.15395, 54.37672 ], [ 71.12151, 54.5804 ], [ 71.17515, 54.64735 ], [ 71.07781, 54.65284 ], [ 70.99774, 54.74058 ], [ 70.91112, 54.87317 ], [ 70.9409, 55.05848 ], [ 70.76852, 55.23043 ], [ 70.46601, 55.22237 ], [ 70.41639, 55.16605 ], [ 70.20063, 55.09731 ], [ 69.93304, 55.16394 ], [ 69.7053, 55.29902 ], [ 69.48628, 55.28513 ], [ 69.37966, 55.32359 ], [ 69.20471, 55.28023 ], [ 69.03674, 55.37045 ], [ 69.02836, 55.23811 ], [ 68.77505, 55.31655 ], [ 68.64694, 55.15331 ], [ 68.30415, 55.13647 ], [ 68.36633, 55.06849 ], [ 68.24901, 54.92079 ], [ 67.86256, 54.92386 ], [ 67.80211, 54.84358 ], [ 67.69672, 54.81308 ], [ 67.32834, 54.81538 ], [ 67.07417, 54.73086 ], [ 66.01484, 54.57539 ], [ 65.90964, 54.65084 ], [ 65.76179, 54.55718 ], [ 65.55275, 54.58507 ], [ 65.51136, 54.51945 ], [ 65.27782, 54.4981 ], [ 65.31312, 54.35856 ], [ 65.23567, 54.28547 ], [ 65.10061, 54.28314 ], [ 64.95391, 54.36365 ], [ 64.75536, 54.3044 ], [ 64.61423, 54.32537 ], [ 64.10045, 54.25829 ], [ 63.97411, 54.14977 ], [ 63.79068, 54.21601 ], [ 63.23851, 54.14052 ], [ 63.09202, 54.05401 ], [ 62.63738, 54.02574 ], [ 62.62218, 53.93064 ], [ 62.5166, 53.86345 ], [ 62.40841, 53.89399 ], [ 62.3479, 53.98152 ], [ 62.08669, 53.99158 ], [ 62.07141, 53.90617 ], [ 61.93821, 53.8984 ], [ 61.70177, 53.96783 ], [ 61.55738, 53.92026 ], [ 61.43208, 54.02931 ], [ 61.32252, 54.02155 ], [ 61.27224, 53.77458 ], [ 61.11265, 53.6706 ], [ 61.2198, 53.61791 ], [ 61.56672, 53.64116 ], [ 61.64179, 53.52702 ], [ 61.58914, 53.45228 ], [ 61.47316, 53.4121 ], [ 61.28709, 53.45849 ], [ 61.23391, 53.34354 ], [ 61.54245, 53.26888 ], [ 61.70444, 53.30797 ], [ 61.81359, 53.22919 ], [ 62.13175, 53.16199 ], [ 62.19602, 53.05015 ], [ 62.16733, 52.95498 ], [ 62.0233, 52.89914 ], [ 61.7987, 52.94538 ], [ 61.62182, 52.90428 ], [ 61.47824, 52.97811 ], [ 61.16093, 52.94651 ], [ 60.7726, 52.69768 ], [ 60.88123, 52.67443 ], [ 60.90531, 52.56987 ], [ 61.0192, 52.54008 ], [ 61.10595, 52.3143 ], [ 60.74276, 52.11238 ], [ 60.52283, 52.10175 ], [ 60.19803, 51.9389 ], [ 60.55461, 51.83352 ], [ 60.55666, 51.7417 ], [ 60.48638, 51.69575 ], [ 60.9563, 51.66168 ], [ 60.97324, 51.56357 ], [ 61.02821, 51.52042 ], [ 61.505, 51.45935 ], [ 61.73371, 51.27975 ], [ 61.71087, 51.2122 ], [ 61.6091, 51.18039 ], [ 61.4775, 50.76372 ], [ 60.82497, 50.60673 ], [ 60.30811, 50.62164 ], [ 60.14419, 50.78129 ], [ 60.04013, 50.76267 ], [ 60.03802, 50.64431 ], [ 59.83658, 50.49067 ], [ 59.50366, 50.44446 ], [ 59.41208, 50.5204 ], [ 59.40752, 50.5865 ], [ 58.87397, 50.64752 ], [ 58.75108, 50.75904 ], [ 58.63651, 50.76234 ], [ 58.61717, 50.82102 ], [ 58.55671, 50.83518 ], [ 58.5548, 51.00639 ], [ 58.36807, 51.02613 ], [ 58.29841, 51.09797 ], [ 58.16644, 51.01243 ], [ 57.81701, 51.06097 ], [ 57.79196, 50.87955 ], [ 57.57432, 50.88038 ], [ 57.50648, 50.82501 ], [ 57.2991, 50.89787 ], [ 57.16343, 51.04051 ], [ 56.77757, 51.03494 ], [ 56.79957, 50.96934 ], [ 56.71622, 50.92326 ], [ 56.51267, 51.00062 ], [ 56.49571, 50.9305 ], [ 56.37383, 50.8525 ], [ 56.2094, 50.861 ], [ 56.17464, 50.72225 ], [ 56.08227, 50.65105 ], [ 55.71887, 50.49804 ], [ 55.47464, 50.61864 ], [ 55.36266, 50.60933 ], [ 55.02561, 50.77932 ], [ 55.02412, 50.85762 ], [ 54.65958, 50.97017 ], [ 54.74457, 50.91284 ], [ 54.72781, 50.8079 ], [ 54.78157, 50.61327 ], [ 54.64616, 50.49797 ], [ 54.54151, 50.47668 ], [ 54.36506, 50.61075 ], [ 54.42749, 50.80938 ], [ 54.17041, 50.92215 ], [ 54.08016, 51.06506 ], [ 53.99397, 51.1117 ], [ 53.63629, 51.18537 ], [ 53.55134, 51.28157 ], [ 53.53716, 51.3739 ], [ 53.22514, 51.45484 ], [ 52.94984, 51.40401 ], [ 52.78196, 51.44728 ], [ 52.54097, 51.40815 ], [ 52.31873, 51.68726 ], [ 52.09789, 51.60852 ], [ 51.90648, 51.62539 ], [ 51.84275, 51.56811 ], [ 51.85604, 51.46959 ], [ 51.63571, 51.40443 ], [ 51.58176, 51.45817 ], [ 51.26264, 51.44307 ], [ 51.19473, 51.52671 ], [ 51.23949, 51.62827 ], [ 50.87969, 51.63323 ], [ 50.84618, 51.54813 ], [ 50.76797, 51.52409 ], [ 50.62893, 51.56545 ], [ 50.59199, 51.43686 ], [ 50.43973, 51.36955 ], [ 50.38884, 51.28291 ], [ 50.02016, 51.19171 ], [ 49.77528, 51.05602 ], [ 49.46337, 51.05153 ], [ 49.43494, 51.00972 ], [ 49.49517, 50.88162 ], [ 49.45624, 50.81043 ], [ 49.14368, 50.73163 ], [ 48.83899, 50.54948 ], [ 48.71294, 50.54935 ], [ 48.77469, 50.29923 ], [ 48.95297, 50.02451 ], [ 48.76092, 49.87291 ], [ 48.4479, 49.75097 ], [ 48.20312, 49.82278 ], [ 48.05998, 50.05301 ], [ 47.89502, 50.20414 ], [ 47.59166, 50.40748 ], [ 47.51007, 50.37976 ], [ 47.36594, 50.27447 ], [ 47.38377, 50.05208 ], [ 47.19074, 49.88336 ], [ 46.94498, 49.81672 ], [ 46.85039, 49.38503 ], [ 47.0187, 49.27955 ], [ 47.09872, 49.14378 ], [ 47.0122, 48.9948 ], [ 46.80537, 48.89006 ], [ 46.59034, 48.46934 ], [ 47.15755, 48.3071 ], [ 47.17553, 48.15345 ], [ 47.26121, 48.07877 ], [ 47.14475, 47.95903 ], [ 47.22767, 47.87353 ], [ 47.23594, 47.80066 ], [ 47.35203, 47.76545 ], [ 47.41085, 47.8885 ], [ 47.66885, 47.80996 ], [ 48.04813, 47.81218 ], [ 48.23329, 47.7388 ], [ 48.46943, 47.47112 ], [ 48.56782, 47.43402 ], [ 49.04755, 46.75114 ], [ 48.92563, 46.6427 ], [ 48.62393, 46.65237 ], [ 49.19315, 46.4275 ], [ 49.52308, 46.24281 ], [ 49.71829, 46.23479 ], [ 49.93666, 46.04634 ], [ 49.11256, 45.65282 ], [ 49.01144, 45.47855 ], [ 48.86567, 45.38544 ], [ 48.67183, 45.35084 ], [ 48.27987, 45.40203 ], [ 48.05696, 45.24572 ], [ 47.64786, 45.15848 ], [ 47.37386, 44.72613 ], [ 47.59802, 44.74029 ], [ 47.78865, 44.65814 ], [ 47.89509, 44.44452 ], [ 47.8084, 44.24603 ], [ 48.04129, 44.20116 ], [ 48.1644, 44.09189 ], [ 48.19536, 43.98996 ], [ 48.16466, 43.87705 ], [ 47.89469, 43.61146 ], [ 47.85146, 43.47209 ], [ 47.88465, 43.29552 ], [ 47.84597, 43.11901 ], [ 47.97945, 42.99383 ], [ 48.23971, 42.57976 ], [ 48.60773, 42.16834 ], [ 48.86453, 41.95753 ], [ 48.62989, 41.80192 ], [ 48.41078, 41.55137 ], [ 48.1129, 41.44532 ], [ 47.90696, 41.17502 ], [ 47.77601, 41.1355 ], [ 47.63965, 41.17394 ], [ 47.55554, 41.14866 ], [ 47.45024, 41.21199 ] ] ], [ [ [ -180.0, 72.2916 ], [ -169.907891, 72.234092 ], [ -168.684085, 65.990095 ], [ -168.725284, 65.414875 ], [ -172.074188, 64.033556 ], [ -180.0, 62.26134 ], [ -180.0, 72.29053 ], [ -180.0, 72.2916 ] ] ], [ [ [ 22.22727, 54.33593 ], [ 21.44629, 54.31282 ], [ 21.37827, 54.32501 ], [ 21.26116, 54.32314 ], [ 20.74068, 54.36326 ], [ 20.63083, 54.3604 ], [ 20.58391, 54.37189 ], [ 20.33136, 54.39511 ], [ 19.64733, 54.44727 ], [ 19.40837, 54.61169 ], [ 19.50858, 54.68355 ], [ 19.58461, 54.77262 ], [ 19.57351, 54.86918 ], [ 19.58918, 54.95461 ], [ 19.63488, 55.02533 ], [ 19.72775, 55.10661 ], [ 19.82198, 55.14569 ], [ 19.9205, 55.16401 ], [ 20.20131, 55.16615 ], [ 20.39793, 55.18633 ], [ 20.65365, 55.3899 ], [ 20.95439, 55.28694 ], [ 21.09934, 55.26235 ], [ 21.27184, 55.25158 ], [ 21.38577, 55.29945 ], [ 21.43505, 55.25676 ], [ 21.45261, 55.22705 ], [ 21.50256, 55.19329 ], [ 21.56952, 55.20409 ], [ 21.65011, 55.18673 ], [ 21.71247, 55.15668 ], [ 21.72595, 55.13858 ], [ 21.81586, 55.12522 ], [ 21.85347, 55.1025 ], [ 21.92037, 55.08658 ], [ 21.96346, 55.0801 ], [ 21.99622, 55.09254 ], [ 22.03355, 55.09001 ], [ 22.04595, 55.07927 ], [ 22.0409, 55.04771 ], [ 22.07676, 55.03107 ], [ 22.11668, 55.03312 ], [ 22.13061, 55.05093 ], [ 22.1606, 55.06165 ], [ 22.29012, 55.071 ], [ 22.47057, 55.05064 ], [ 22.59123, 55.07575 ], [ 22.60258, 55.02726 ], [ 22.64782, 54.9875 ], [ 22.65115, 54.9726 ], [ 22.65624, 54.9868 ], [ 22.68043, 54.99268 ], [ 22.69528, 54.97819 ], [ 22.72969, 54.96771 ], [ 22.73776, 54.95228 ], [ 22.76934, 54.94047 ], [ 22.77229, 54.92998 ], [ 22.78564, 54.92998 ], [ 22.79607, 54.90969 ], [ 22.82176, 54.91769 ], [ 22.85917, 54.89211 ], [ 22.8486, 54.869 ], [ 22.87459, 54.8553 ], [ 22.86936, 54.84295 ], [ 22.89215, 54.81546 ], [ 22.88011, 54.80362 ], [ 22.88351, 54.78865 ], [ 22.86373, 54.78234 ], [ 22.86419, 54.77399 ], [ 22.84556, 54.76117 ], [ 22.81955, 54.75959 ], [ 22.80989, 54.7428 ], [ 22.78026, 54.74346 ], [ 22.74835, 54.72438 ], [ 22.75458, 54.7047 ], [ 22.73321, 54.68658 ], [ 22.74301, 54.68216 ], [ 22.74373, 54.66534 ], [ 22.76275, 54.65463 ], [ 22.75463, 54.63005 ], [ 22.69213, 54.58511 ], [ 22.71956, 54.56434 ], [ 22.68861, 54.53217 ], [ 22.70476, 54.50897 ], [ 22.7093, 54.45891 ], [ 22.74021, 54.44744 ], [ 22.7962, 54.35926 ], [ 22.22727, 54.33593 ] ] ] ] } } ] } osmium-tool-1.14.0/test/extract/polygon-russia-west.geojson000066400000000000000000000013221420023413700240450ustar00rootroot00000000000000{ "type": "Feature", "properties": { "name": "polygon" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -180, 72.2916 ], [ -180, 72.29053 ], [ -180, 62.26134 ], [ -172.074188, 64.033556 ], [ -168.725284, 65.414875 ], [ -168.684085, 65.990095 ], [ -169.907891, 72.234092 ], [ -180, 72.2916 ] ] ] ] } } osmium-tool-1.14.0/test/extract/polygon-two-outer.poly000066400000000000000000000001701420023413700230430ustar00rootroot00000000000000foo 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.14.0/test/extract/polygon-two-ways.osm.opl000066400000000000000000000002621420023413700232760ustar00rootroot00000000000000n10 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.14.0/test/extract/polygon-us-alaska.geojson000066400000000000000000000047271420023413700234540ustar00rootroot00000000000000{ "type": "Feature", "properties": { "name": "none" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 180, 54.19453 ], [ 180, 51.11044 ], [ 171.7602, 51.13801 ], [ 171.8152, 54.08518 ], [ 180, 54.19453 ] ] ], [ [ [ -180, 49.80942 ], [ -180, 60.09775 ], [ -169.0686, 65.40802 ], [ -168.9478, 66.01132 ], [ -169.1147, 71.19564 ], [ -140.9715, 72.98845 ], [ -140.9775, 60.31064 ], [ -139.0488, 60.36127 ], [ -139.1508, 60.10438 ], [ -138.6734, 59.9144 ], [ -138.6363, 59.81201 ], [ -137.5517, 59.23372 ], [ -137.4664, 58.94576 ], [ -136.7081, 59.21237 ], [ -136.3698, 59.61097 ], [ -135.3911, 59.82867 ], [ -134.7243, 59.3922 ], [ -134.4972, 59.15539 ], [ -133.3385, 58.42044 ], [ -131.6441, 56.6537 ], [ -129.7998, 56.04294 ], [ -130.1171, 55.74696 ], [ -129.8715, 55.26134 ], [ -130.5575, 54.64634 ], [ -131.6262, 54.4781 ], [ -132.6944, 54.45706 ], [ -133.7018, 54.51622 ], [ -133.5648, 53.42951 ], [ -180, 49.80942 ] ] ] ] } }osmium-tool-1.14.0/test/extract/polygon-us-alaska.poly000066400000000000000000000020701420023413700227600ustar00rootroot00000000000000none 1 1.80E+02 5.419453E+01 1.80E+02 5.111044E+01 1.717602E+02 5.113801E+01 1.718152E+02 5.408518E+01 1.80E+02 5.419453E+01 END 2 -1.80E+02 4.980942E+01 -1.80E+02 6.009775E+01 -1.690686E+02 6.540802E+01 -1.689478E+02 6.601132E+01 -1.691147E+02 7.119564E+01 -1.409715E+02 7.298845E+01 -1.409775E+02 6.031064E+01 -1.390488E+02 6.036127E+01 -1.391508E+02 6.010438E+01 -1.386734E+02 5.991440E+01 -1.386363E+02 5.981201E+01 -1.375517E+02 5.923372E+01 -1.374664E+02 5.894576E+01 -1.367081E+02 5.921237E+01 -1.363698E+02 5.961097E+01 -1.353911E+02 5.982867E+01 -1.347243E+02 5.939220E+01 -1.344972E+02 5.915539E+01 -1.333385E+02 5.842044E+01 -1.316441E+02 5.665370E+01 -1.297998E+02 5.604294E+01 -1.301171E+02 5.574696E+01 -1.298715E+02 5.526134E+01 -1.305575E+02 5.464634E+01 -1.316262E+02 5.447810E+01 -1.326944E+02 5.445706E+01 -1.337018E+02 5.451622E+01 -1.335648E+02 5.342951E+01 -1.80E+02 4.980942E+01 END END osmium-tool-1.14.0/test/extract/polygon-way.osm.opl000066400000000000000000000001311420023413700222770ustar00rootroot00000000000000n10 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.14.0/test/extract/test_unit.cpp000066400000000000000000000220311420023413700212260ustar00rootroot00000000000000 #include "test.hpp" // IWYU pragma: keep #include "exception.hpp" #include "geojson_file_parser.hpp" #include "geometry_util.hpp" #include "osm_file_parser.hpp" #include "poly_file_parser.hpp" #include 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); } } TEST_CASE("Ring orientation (clockwise)") { using oc = osmium::geom::Coordinates; std::vector c = {oc{0, 0}, oc{0, 1}, oc{1, 1}, oc{1, 0}, oc{0, 0}}; REQUIRE(calculate_double_area(c) == Approx(-2.0)); REQUIRE_FALSE(is_ccw(c)); } TEST_CASE("Ring orientation (counter-clockwise)") { using oc = osmium::geom::Coordinates; std::vector c = {oc{0, 0}, oc{1, 0}, oc{1, 1}, oc{0, 1}, oc{0, 0}}; REQUIRE(calculate_double_area(c) == Approx(2.0)); REQUIRE(is_ccw(c)); } osmium-tool-1.14.0/test/extract/two-line.poly000066400000000000000000000000101420023413700211400ustar00rootroot00000000000000foo bar osmium-tool-1.14.0/test/extract/two-polygons-empty-line.poly000066400000000000000000000002731420023413700241570ustar00rootroot00000000000000foo 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.14.0/test/extract/two-polygons.poly000066400000000000000000000002721420023413700220750ustar00rootroot00000000000000foo 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.14.0/test/extract/w42394837.opl000066400000000000000000000020511420023413700203360ustar00rootroot00000000000000n529267768 v4 dV c18157685 t2013-10-03T09:27:25Z i90780 uVerdy_p T x180 y51.7940888 n529268301 v4 dV c18109681 t2013-09-30T12:42:56Z i90780 uVerdy_p T x180 y52.1384488 n2477601610 v2 dV c18157685 t2013-10-03T09:27:24Z i90780 uVerdy_p T x180 y51.8434451 n2477601612 v2 dV c18157685 t2013-10-03T09:27:24Z i90780 uVerdy_p T x180 y51.8927474 n2477601614 v2 dV c18157685 t2013-10-03T09:27:24Z i90780 uVerdy_p T x180 y51.9419957 n2477601616 v2 dV c18157685 t2013-10-03T09:27:24Z i90780 uVerdy_p T x180 y51.9911899 n2477601618 v2 dV c18157685 t2013-10-03T09:27:24Z i90780 uVerdy_p T x180 y52.0403302 n2477601621 v2 dV c18157685 t2013-10-03T09:27:24Z i90780 uVerdy_p T x180 y52.0894164 w42394837 v7 dV c74735267 t2019-09-20T21:14:03Z i8407767 uВаÑиль%20%Бойчук Tclosure_segment=yes,maritime=yes,name=Antimeridian%20%(180°%20%East),note=segment%20%closing%20%the%20%nautical%20%border%20%in%20%2%20%polygons%20%left%20%and%20%right%20%of%20%the%20%180th%20%meridian Nn529267768,n2477601610,n2477601612,n2477601614,n2477601616,n2477601618,n2477601621,n529268301 osmium-tool-1.14.0/test/extract/w42394837.osm000066400000000000000000000042301420023413700203430ustar00rootroot00000000000000 osmium-tool-1.14.0/test/extract/w46113981.opl000066400000000000000000000020311420023413700203250ustar00rootroot00000000000000n529215046 v4 dV c18157685 t2013-10-03T09:27:24Z i90780 uVerdy_p T x-180 y51.7940888 n529215726 v4 dV c18112005 t2013-09-30T14:47:23Z i90780 uVerdy_p T x-180 y52.138489 n2480990121 v1 dV c18157685 t2013-10-03T09:22:55Z i90780 uVerdy_p T x-180 y51.8434509 n2480990124 v1 dV c18157685 t2013-10-03T09:22:55Z i90780 uVerdy_p T x-180 y51.892759 n2480990126 v1 dV c18157685 t2013-10-03T09:22:55Z i90780 uVerdy_p T x-180 y51.942013 n2480990128 v1 dV c18157685 t2013-10-03T09:22:56Z i90780 uVerdy_p T x-180 y51.991213 n2480990129 v1 dV c18157685 t2013-10-03T09:22:56Z i90780 uVerdy_p T x-180 y52.0403589 n2480990140 v1 dV c18157685 t2013-10-03T09:22:56Z i90780 uVerdy_p T x-180 y52.0894509 w46113981 v7 dV c24927728 t2014-08-22T09:27:42Z i1781102 uelazarev Tclosure_segment=yes,maritime=yes,name=Antimeridian%20%(180°%20%West),note=segment%20%closing%20%the%20%nautical%20%border%20%in%20%2%20%polygons%20%left%20%and%20%right%20%of%20%the%20%180th%20%meridian Nn529215726,n2480990140,n2480990129,n2480990128,n2480990126,n2480990124,n2480990121,n529215046 osmium-tool-1.14.0/test/extract/w46113981.osm000066400000000000000000000042171420023413700203410ustar00rootroot00000000000000 osmium-tool-1.14.0/test/extract/wrong-geometry-type.geojson000066400000000000000000000001131420023413700240330ustar00rootroot00000000000000{ "type": "Feature", "geometry": { "type": "Point" } } osmium-tool-1.14.0/test/fileinfo/000077500000000000000000000000001420023413700166275ustar00rootroot00000000000000osmium-tool-1.14.0/test/fileinfo/CMakeLists.txt000066400000000000000000000203301420023413700213650ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - fileinfo # #----------------------------------------------------------------------------- if(NOT WIN32) function(check_fileinfo _name _options _input _output) check_output(fileinfo ${_name} "fileinfo ${_options} fileinfo/${_input}" "fileinfo/${_output}") endfunction() check_fileinfo(fi1-extended "--extended --crc" fi1.osm fi1-result.txt) endif() #----------------------------------------------------------------------------- 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) #----------------------------------------------------------------------------- # Test the metadata properties #----------------------------------------------------------------------------- # The input file has objects with only version+timestamp and objects with all metadata attributes. # searching for metadata.all_objects.version add_test(NAME fileinfo-metadata-mixed-all-version COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi2.osm -e -g metadata.all_objects.version) set_tests_properties(fileinfo-metadata-mixed-all-version PROPERTIES PASS_REGULAR_EXPRESSION "^yes\n$") # The input file has objects with only version+timestamp and objects with all metadata attributes. # searching for metadata.all_objects.timestamp add_test(NAME fileinfo-metadata-mixed-all-timestamp COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi2.osm -e -g metadata.all_objects.timestamp) set_tests_properties(fileinfo-metadata-mixed-all-timestamp PROPERTIES PASS_REGULAR_EXPRESSION "^yes\n$") # The input file has objects with only version+timestamp and objects with all metadata attributes. # searching for metadata.all_objects.changeset add_test(NAME fileinfo-metadata-mixed-all-changeset COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi2.osm -e -g metadata.all_objects.changeset) set_tests_properties(fileinfo-metadata-mixed-all-changeset PROPERTIES PASS_REGULAR_EXPRESSION "^no\n$") # The input file has objects with only version+timestamp and objects with all metadata attributes. # searching for metadata.some_objects.version add_test(NAME fileinfo-metadata-mixed-some-version COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi2.osm -e -g metadata.some_objects.version) set_tests_properties(fileinfo-metadata-mixed-some-version PROPERTIES PASS_REGULAR_EXPRESSION "^yes\n$") # The input file has objects with only version+timestamp and objects with all metadata attributes. # searching for metadata.some_objects.timestamp add_test(NAME fileinfo-metadata-mixed-some-timestamp COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi2.osm -e -g metadata.some_objects.timestamp) set_tests_properties(fileinfo-metadata-mixed-some-timestamp PROPERTIES PASS_REGULAR_EXPRESSION "^yes\n$") # The input file has objects with only version+timestamp and objects with all metadata attributes. # searching for metadata.some_objects.changeset add_test(NAME fileinfo-metadata-mixed-some-changeset COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi2.osm -e -g metadata.some_objects.changeset) set_tests_properties(fileinfo-metadata-mixed-some-changeset PROPERTIES PASS_REGULAR_EXPRESSION "^yes\n$") # The input file has objects with only version+timestamp and objects with all metadata attributes. # searching for metadata.some_objects.uid add_test(NAME fileinfo-metadata-mixed-some-uid COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi2.osm -e -g metadata.some_objects.uid) set_tests_properties(fileinfo-metadata-mixed-some-uid PROPERTIES PASS_REGULAR_EXPRESSION "^yes\n$") # The input file has objects with only version+timestamp and objects with all metadata attributes. # searching for metadata.some_objects.user add_test(NAME fileinfo-metadata-mixed-some-user COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi2.osm -e -g metadata.some_objects.user) set_tests_properties(fileinfo-metadata-mixed-some-user PROPERTIES PASS_REGULAR_EXPRESSION "^yes\n$") # The input file contains only objects with version+timestamp. # searching for metadata.all_objects.version add_test(NAME fileinfo-metadata-homogenous-all-version COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi3.osm -e -g metadata.all_objects.version) set_tests_properties(fileinfo-metadata-homogenous-all-version PROPERTIES PASS_REGULAR_EXPRESSION "^yes\n$") # The input file contains only objects with version+timestamp. # searching for metadata.all_objects.timestamp add_test(NAME fileinfo-metadata-homogenous-all-timestamp COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi3.osm -e -g metadata.all_objects.timestamp) set_tests_properties(fileinfo-metadata-homogenous-all-timestamp PROPERTIES PASS_REGULAR_EXPRESSION "^yes\n$") # The input file contains only objects with version+timestamp. # searching for metadata.all_objects.changeset add_test(NAME fileinfo-metadata-homogenous-all-changeset COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi3.osm -e -g metadata.all_objects.changeset) set_tests_properties(fileinfo-metadata-homogenous-all-changeset PROPERTIES PASS_REGULAR_EXPRESSION "^no\n$") # The input file contains only objects with version+timestamp. # searching for metadata.all_objects.uid add_test(NAME fileinfo-metadata-homogenous-all-uid COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi3.osm -e -g metadata.all_objects.uid) set_tests_properties(fileinfo-metadata-homogenous-all-uid PROPERTIES PASS_REGULAR_EXPRESSION "^no\n$") # The input file contains only objects with version+timestamp. # searching for metadata.all_objects.user add_test(NAME fileinfo-metadata-homogenous-all-user COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi3.osm -e -g metadata.all_objects.user) set_tests_properties(fileinfo-metadata-homogenous-all-user PROPERTIES PASS_REGULAR_EXPRESSION "^no\n$") # The input file contains only objects with version+timestamp. # searching for metadata.some_objects.version add_test(NAME fileinfo-metadata-homogenous-some-version COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi3.osm -e -g metadata.some_objects.version) set_tests_properties(fileinfo-metadata-homogenous-some-version PROPERTIES PASS_REGULAR_EXPRESSION "^yes\n$") # The input file contains only objects with version+timestamp. # searching for metadata.some_objects.timestamp add_test(NAME fileinfo-metadata-homogenous-some-timestamp COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi3.osm -e -g metadata.some_objects.timestamp) set_tests_properties(fileinfo-metadata-homogenous-some-timestamp PROPERTIES PASS_REGULAR_EXPRESSION "^yes\n$") # The input file contains only objects with version+timestamp. # searching for metadata.some_objects.changeset add_test(NAME fileinfo-metadata-homogenous-some-changeset COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi3.osm -e -g metadata.some_objects.changeset) set_tests_properties(fileinfo-metadata-homogenous-some-changeset PROPERTIES PASS_REGULAR_EXPRESSION "^no\n$") # The input file contains only objects with version+timestamp. # searching for metadata.some_objects.uid add_test(NAME fileinfo-metadata-homogenous-some-uid COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi3.osm -e -g metadata.some_objects.uid) set_tests_properties(fileinfo-metadata-homogenous-some-uid PROPERTIES PASS_REGULAR_EXPRESSION "^no\n$") # The input file contains only objects with version+timestamp. # searching for metadata.some_objects.user add_test(NAME fileinfo-metadata-homogenous-some-user COMMAND osmium fileinfo ${CMAKE_SOURCE_DIR}/test/fileinfo/fi3.osm -e -g metadata.some_objects.user) set_tests_properties(fileinfo-metadata-homogenous-some-user PROPERTIES PASS_REGULAR_EXPRESSION "^no\n$") #----------------------------------------------------------------------------- osmium-tool-1.14.0/test/fileinfo/fi1-result.txt000066400000000000000000000016611420023413700213670ustar00rootroot00000000000000File: Name: fileinfo/fi1.osm Format: XML Compression: none Size: 630 Header: Bounding boxes: With history: no Options: generator=testdata version=0.6 xml_josm_upload=false 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: 95828746 Number of changesets: 0 Number of nodes: 3 Number of ways: 2 Number of relations: 0 Smallest changeset ID: 0 Smallest node ID: 1 Smallest way ID: -4 Smallest relation ID: 0 Largest changeset ID: 0 Largest node ID: 4 Largest way ID: -3 Largest relation ID: 0 Number of buffers: 1 (avg 5 objects per buffer) Sum of buffer sizes: 224 (0 GB) Sum of buffer capacities: 1048576 (0.001 GB, 0% full) Metadata: All objects have following metadata attributes: all Some objects have following metadata attributes: all osmium-tool-1.14.0/test/fileinfo/fi1.osm000066400000000000000000000011661420023413700200320ustar00rootroot00000000000000 osmium-tool-1.14.0/test/fileinfo/fi2.osm000066400000000000000000000005621420023413700200320ustar00rootroot00000000000000 osmium-tool-1.14.0/test/fileinfo/fi3.osm000066400000000000000000000005201420023413700200250ustar00rootroot00000000000000 osmium-tool-1.14.0/test/formats/000077500000000000000000000000001420023413700165075ustar00rootroot00000000000000osmium-tool-1.14.0/test/formats/CMakeLists.txt000066400000000000000000000056041420023413700212540ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # 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,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,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.14.0/test/formats/empty-nocompression.osm.pbf000066400000000000000000000000661420023413700240310ustar00rootroot00000000000000 OSMHeader% #"OsmSchema-V0.6" DenseNodes‚testosmium-tool-1.14.0/test/formats/empty-nodensenodes-nometadata.osm.pbf000066400000000000000000000000641420023413700257300ustar00rootroot00000000000000 OSMHeader#xœSâó/Î NÎHÍMÔ 3Ð3kbd)I-.R›osmium-tool-1.14.0/test/formats/empty-nodensenodes.osm.pbf000066400000000000000000000000641420023413700236150ustar00rootroot00000000000000 OSMHeader#xœSâó/Î NÎHÍMÔ 3Ð3kbd)I-.R›osmium-tool-1.14.0/test/formats/empty-nometadata.osm.pbf000066400000000000000000000001001420023413700232350ustar00rootroot00000000000000 OSMHeader/#+xœSâó/Î NÎHÍMÔ 3Ð3SârIÍ+NõËOI-nbd)I-.¿` #osmium-tool-1.14.0/test/formats/empty.osm000066400000000000000000000001421420023413700203620ustar00rootroot00000000000000 osmium-tool-1.14.0/test/formats/empty.osm.opl000066400000000000000000000000001420023413700211440ustar00rootroot00000000000000osmium-tool-1.14.0/test/formats/empty.osm.pbf000066400000000000000000000001001420023413700211220ustar00rootroot00000000000000 OSMHeader/#+xœSâó/Î NÎHÍMÔ 3Ð3SârIÍ+NõËOI-nbd)I-.¿` #osmium-tool-1.14.0/test/formats/f1-nocompression.osm.pbf000066400000000000000000000006041420023413700231770ustar00rootroot00000000000000 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.14.0/test/formats/f1-nodensenodes-nometadata.osm.pbf000066400000000000000000000004411420023413700250770ustar00rootroot00000000000000 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.14.0/test/formats/f1-nodensenodes.osm.pbf000066400000000000000000000006221420023413700227650ustar00rootroot00000000000000 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.14.0/test/formats/f1-nometadata.osm.pbf000066400000000000000000000004531420023413700224200ustar00rootroot00000000000000 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.14.0/test/formats/f1.osm000066400000000000000000000022341420023413700175360ustar00rootroot00000000000000 osmium-tool-1.14.0/test/formats/f1.osm.opl000066400000000000000000000006601420023413700203300ustar00rootroot00000000000000n10 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.14.0/test/formats/f1.osm.pbf000066400000000000000000000006241420023413700203050ustar00rootroot00000000000000 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.14.0/test/getid/000077500000000000000000000000001420023413700161305ustar00rootroot00000000000000osmium-tool-1.14.0/test/getid/CMakeLists.txt000066400000000000000000000040631420023413700206730ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - getid # #----------------------------------------------------------------------------- function(check_getid _name _input _output) check_output(getid ${_name} "getid --generator=test --output-header=xml_josm_upload=false -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 --output-header=xml_josm_upload=false -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() function(check_getid_r_fail _name _input) check_output(getid ${_name} "getid -r --generator=test -f osm getid/source.osm -I getid/${_input}.osm" "getid/out-empty.osm" 1) check_output(getid ${_name}-i "getid -r --generator=test -f osm getid/source.osm -i getid/${_input}.id" "getid/out-empty.osm" 1) 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_fail(missing-n19 in19) check_getid_r_fail(missing-w29 in29) check_getid_r_fail(missing-r39 in39) check_getid_r(relloop relloop relloop relloop-out) #----------------------------------------------------------------------------- osmium-tool-1.14.0/test/getid/idfile000066400000000000000000000000741420023413700173100ustar00rootroot00000000000000n11 n12 foo n10 n13 # comment # comment w21 osmium-tool-1.14.0/test/getid/in10.id000066400000000000000000000000041420023413700172070ustar00rootroot00000000000000n10 osmium-tool-1.14.0/test/getid/in10.osm000066400000000000000000000003271420023413700174210ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/in19.id000066400000000000000000000000041420023413700172200ustar00rootroot00000000000000n19 osmium-tool-1.14.0/test/getid/in19.osm000066400000000000000000000003271420023413700174320ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/in21.id000066400000000000000000000000041420023413700172110ustar00rootroot00000000000000w21 osmium-tool-1.14.0/test/getid/in21.osm000066400000000000000000000003641420023413700174240ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/in29.id000066400000000000000000000000041420023413700172210ustar00rootroot00000000000000w29 osmium-tool-1.14.0/test/getid/in29.osm000066400000000000000000000003641420023413700174340ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/in30.id000066400000000000000000000000041420023413700172110ustar00rootroot00000000000000r30 osmium-tool-1.14.0/test/getid/in30.osm000066400000000000000000000005271420023413700174250ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/in31.id000066400000000000000000000000041420023413700172120ustar00rootroot00000000000000r31 osmium-tool-1.14.0/test/getid/in31.osm000066400000000000000000000004071420023413700174230ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/in32.id000066400000000000000000000000041420023413700172130ustar00rootroot00000000000000r32 osmium-tool-1.14.0/test/getid/in32.osm000066400000000000000000000004031420023413700174200ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/in39.id000066400000000000000000000000041420023413700172220ustar00rootroot00000000000000r39 osmium-tool-1.14.0/test/getid/in39.osm000066400000000000000000000004031420023413700174270ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/input.osm000066400000000000000000000021321420023413700200050ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/out-empty.osm000066400000000000000000000001421420023413700206100ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/out10.osm000066400000000000000000000003231420023413700176160ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/out21.osm000066400000000000000000000007221420023413700176230ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/out30.osm000066400000000000000000000017021420023413700176220ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/out31.osm000066400000000000000000000021431420023413700176230ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/out32.osm000066400000000000000000000005601420023413700176250ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/output-file.osm000066400000000000000000000013171420023413700211270ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/output.osm000066400000000000000000000007551420023413700202170ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/relloop-out.osm000066400000000000000000000006441420023413700211350ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/relloop.id000066400000000000000000000000101420023413700201110ustar00rootroot00000000000000r30 r31 osmium-tool-1.14.0/test/getid/relloop.osm000066400000000000000000000006501420023413700203250ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/source-no-rr.osm000066400000000000000000000025421420023413700212060ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getid/source.osm000066400000000000000000000030031420023413700201440ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getparents/000077500000000000000000000000001420023413700172105ustar00rootroot00000000000000osmium-tool-1.14.0/test/getparents/CMakeLists.txt000066400000000000000000000022101420023413700217430ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # CMake Config # # Osmium Tool Tests - getparents # #----------------------------------------------------------------------------- function(check_getparents _name _input _ids _output) check_output(getparents ${_name} "getparents --generator=test --output-header=xml_josm_upload=false -f osm getparents/${_input} ${_ids}" "getparents/${_output}") endfunction() function(check_getparents_r _name _input _ids _output) check_output(getparents ${_name}-s "getparents --generator=test --output-header=xml_josm_upload=false -f osm --add-self getparents/${_input} ${_ids}" "getparents/${_output}") endfunction() #----------------------------------------------------------------------------- check_getparents(n10 input.osm n10 out-n10.osm) check_getparents(n12 input.osm n12 out-n12.osm) check_getparents(w20 input.osm w20 out-w20.osm) check_getparents_r(n10 input.osm n10 out-n10-s.osm) check_getparents_r(n12 input.osm n12 out-n12-s.osm) check_getparents_r(w20 input.osm w20 out-w20-s.osm) #----------------------------------------------------------------------------- osmium-tool-1.14.0/test/getparents/input.osm000066400000000000000000000021321420023413700210650ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getparents/out-n10-s.osm000066400000000000000000000006171420023413700213770ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getparents/out-n10.osm000066400000000000000000000004361420023413700211360ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getparents/out-n12-s.osm000066400000000000000000000014031420023413700213730ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getparents/out-n12.osm000066400000000000000000000012221420023413700211320ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getparents/out-w20-s.osm000066400000000000000000000007511420023413700214100ustar00rootroot00000000000000 osmium-tool-1.14.0/test/getparents/out-w20.osm000066400000000000000000000004551420023413700211510ustar00rootroot00000000000000 osmium-tool-1.14.0/test/help/000077500000000000000000000000001420023413700157645ustar00rootroot00000000000000osmium-tool-1.14.0/test/help/CMakeLists.txt000066400000000000000000000011001420023413700205140ustar00rootroot00000000000000#----------------------------------------------------------------------------- # # 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:") do_test(help_topic_unknown "osmium help x" "^Unknown help topic 'x'.\n") #----------------------------------------------------------------------------- osmium-tool-1.14.0/test/include/000077500000000000000000000000001420023413700164575ustar00rootroot00000000000000osmium-tool-1.14.0/test/include/catch.hpp000066400000000000000000024034261420023413700202650ustar00rootroot00000000000000/* * Catch v2.13.8 * Generated: 2022-01-03 21:20:09.589503 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2022 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 // start catch.hpp #define CATCH_VERSION_MAJOR 2 #define CATCH_VERSION_MINOR 13 #define CATCH_VERSION_PATCH 8 #ifdef __clang__ # pragma clang system_header #elif defined __GNUC__ # pragma GCC system_header #endif // start 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 push # pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ // Because REQUIREs trigger GCC's -Wparentheses, and because still // supported version of g++ have only buggy support for _Pragmas, // Wparentheses have to be suppressed globally. # pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wpadded" #endif // end catch_suppress_warnings.h #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL # define CATCH_CONFIG_ALL_PARTS #endif // In the impl file, we want to have access to all parts of the headers // Can also be used to sanely support PCHs #if defined(CATCH_CONFIG_ALL_PARTS) # define CATCH_CONFIG_EXTERNAL_INTERFACES # if defined(CATCH_CONFIG_DISABLE_MATCHERS) # undef CATCH_CONFIG_DISABLE_MATCHERS # endif # if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER # endif #endif #if !defined(CATCH_CONFIG_IMPL_ONLY) // start catch_platform.h // See e.g.: // https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html #ifdef __APPLE__ # include # if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) # define CATCH_PLATFORM_MAC # elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) # define CATCH_PLATFORM_IPHONE # endif #elif defined(linux) || defined(__linux) || defined(__linux__) # define CATCH_PLATFORM_LINUX #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) # define CATCH_PLATFORM_WINDOWS #endif // end catch_platform.h #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED # define CLARA_CONFIG_MAIN # endif #endif // start catch_user_interfaces.h namespace Catch { unsigned int rngSeed(); } // end catch_user_interfaces.h // start catch_tag_alias_autoregistrar.h // start catch_common.h // start catch_compiler_capabilities.h // Detect a number of compiler features - by compiler // The following features are defined: // // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? // CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? // **************** // 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_NO_POSIX_SIGNALS) 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. #ifdef __cplusplus # if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) # define CATCH_CPP14_OR_GREATER # endif # if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) # define CATCH_CPP17_OR_GREATER # endif #endif // Only GCC compiler should be used in this block, so other compilers trying to // mask themselves as GCC should be ignored. #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) #endif #if defined(__clang__) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) // As of this writing, IBM XL's implementation of __builtin_constant_p has a bug // which results in calls to destructors being emitted for each temporary, // without a matching initialization. In practice, this can result in something // like `std::string::~string` being called on an uninitialized value. // // For example, this code will likely segfault under IBM XL: // ``` // REQUIRE(std::string("12") + "34" == "1234") // ``` // // Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. # if !defined(__ibmxl__) && !defined(__CUDACC__) # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ # endif # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) # define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// // Assume that non-Windows platforms support posix signals by default #if !defined(CATCH_PLATFORM_WINDOWS) #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS #endif //////////////////////////////////////////////////////////////////////////////// // We know some environments not to support full POSIX signals #if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS #endif #ifdef __OS400__ # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS # define CATCH_CONFIG_COLOUR_NONE #endif //////////////////////////////////////////////////////////////////////////////// // Android somehow still does not support std::to_string #if defined(__ANDROID__) # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING # define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE #endif //////////////////////////////////////////////////////////////////////////////// // Not all Windows environments support SEH properly #if defined(__MINGW32__) # define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH #endif //////////////////////////////////////////////////////////////////////////////// // PS4 #if defined(__ORBIS__) # define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE #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 // some versions of cygwin (most) do not support std::to_string. Use the libstd check. // https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 # if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING # endif #endif // __CYGWIN__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ #if defined(_MSC_VER) // Universal Windows platform does not support SEH // Or console colours (or console at all...) # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) # define CATCH_CONFIG_COLOUR_NONE # else # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH # endif # if !defined(__clang__) // Handle Clang masquerading for msvc // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ // _MSVC_TRADITIONAL == 0 means new conformant preprocessor // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor # if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) # define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR # endif // MSVC_TRADITIONAL // Only do this if we're not using clang on Windows, which uses `diagnostic push` & `diagnostic pop` # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) # endif // __clang__ #endif // _MSC_VER #if defined(_REENTRANT) || defined(_MSC_VER) // Enable async processing, as -pthread is specified or no additional linking is required # define CATCH_INTERNAL_CONFIG_USE_ASYNC #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// // Check if we are compiled with -fno-exceptions or equivalent #if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) # define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED #endif //////////////////////////////////////////////////////////////////////////////// // DJGPP #ifdef __DJGPP__ # define CATCH_INTERNAL_CONFIG_NO_WCHAR #endif // __DJGPP__ //////////////////////////////////////////////////////////////////////////////// // Embarcadero C++Build #if defined(__BORLANDC__) #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN #endif //////////////////////////////////////////////////////////////////////////////// // Use of __COUNTER__ is suppressed during code analysis in // CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly // handled by it. // Otherwise all supported compilers support COUNTER macro, // but user still might want to turn it off #if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) #define CATCH_INTERNAL_CONFIG_COUNTER #endif //////////////////////////////////////////////////////////////////////////////// // RTX is a special version of Windows that is real time. // This means that it is detected as Windows, but does not provide // the same set of capabilities as real Windows does. #if defined(UNDER_RTSS) || defined(RTX64_BUILD) #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH #define CATCH_INTERNAL_CONFIG_NO_ASYNC #define CATCH_CONFIG_COLOUR_NONE #endif #if !defined(_GLIBCXX_USE_C99_MATH_TR1) #define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER #endif // Various stdlib support checks that require __has_include #if defined(__has_include) // Check if string_view is available and usable #if __has_include() && defined(CATCH_CPP17_OR_GREATER) # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW #endif // Check if optional is available and usable # if __has_include() && defined(CATCH_CPP17_OR_GREATER) # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) // Check if byte is available and usable # if __has_include() && defined(CATCH_CPP17_OR_GREATER) # include # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) # define CATCH_INTERNAL_CONFIG_CPP17_BYTE # endif # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) // Check if variant is available and usable # if __has_include() && defined(CATCH_CPP17_OR_GREATER) # if defined(__clang__) && (__clang_major__ < 8) // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 // fix should be in clang 8, workaround in libstdc++ 8.2 # include # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) # define CATCH_CONFIG_NO_CPP17_VARIANT # else # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) # else # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT # endif // defined(__clang__) && (__clang_major__ < 8) # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) #endif // defined(__has_include) #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER #endif #if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_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_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_CONFIG_POSIX_SIGNALS #endif // This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. #if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) # define CATCH_CONFIG_WCHAR #endif #if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) # define CATCH_CONFIG_CPP11_TO_STRING #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) # define CATCH_CONFIG_CPP17_OPTIONAL #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) # define CATCH_CONFIG_CPP17_STRING_VIEW #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) # define CATCH_CONFIG_CPP17_VARIANT #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) # define CATCH_CONFIG_CPP17_BYTE #endif #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) # define CATCH_INTERNAL_CONFIG_NEW_CAPTURE #endif #if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) # define CATCH_CONFIG_NEW_CAPTURE #endif #if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) # define CATCH_CONFIG_DISABLE_EXCEPTIONS #endif #if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) # define CATCH_CONFIG_POLYFILL_ISNAN #endif #if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) # define CATCH_CONFIG_USE_ASYNC #endif #if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) # define CATCH_CONFIG_ANDROID_LOGWRITE #endif #if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) # define CATCH_CONFIG_GLOBAL_NEXTAFTER #endif // Even if we do not think the compiler has that warning, we still have // to provide a macro that can be used by the code. #if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION #endif #if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS #endif // The goal of this macro is to avoid evaluation of the arguments, but // still have the compiler warn on problems inside... #if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) #endif #if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #elif defined(__clang__) && (__clang_major__ < 5) # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) #define CATCH_TRY if ((true)) #define CATCH_CATCH_ALL if ((false)) #define CATCH_CATCH_ANON(type) if ((false)) #else #define CATCH_TRY try #define CATCH_CATCH_ALL catch (...) #define CATCH_CATCH_ANON(type) catch (type) #endif #if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) #define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #endif // end catch_compiler_capabilities.h #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 #include #include #include // We need a dummy global operator<< so we can bring it into Catch namespace later struct Catch_global_namespace_dummy {}; std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); namespace Catch { struct CaseSensitive { enum Choice { Yes, No }; }; class NonCopyable { NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; NonCopyable& operator = ( NonCopyable && ) = delete; protected: NonCopyable(); virtual ~NonCopyable(); }; struct SourceLineInfo { SourceLineInfo() = delete; SourceLineInfo( char const* _file, std::size_t _line ) noexcept : file( _file ), line( _line ) {} SourceLineInfo( SourceLineInfo const& other ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo( SourceLineInfo&& ) noexcept = default; SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; bool empty() const noexcept { return file[0] == '\0'; } bool operator == ( SourceLineInfo const& other ) const noexcept; bool operator < ( SourceLineInfo const& other ) const noexcept; char const* file; std::size_t line; }; std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); // Bring in operator<< from global namespace into Catch namespace // This is necessary because the overload of operator<< above makes // lookup stop at namespace Catch using ::operator<<; // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as // >> stuff +StreamEndStop struct StreamEndStop { std::string operator+() const; }; template T const& operator + ( T const& value, StreamEndStop ) { return value; } } #define CATCH_INTERNAL_LINEINFO \ ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) // end catch_common.h namespace Catch { struct RegistrarForTagAliases { RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; } // end namespace Catch #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION // end catch_tag_alias_autoregistrar.h // start catch_test_registry.h // start catch_interfaces_testcase.h #include namespace Catch { class TestSpec; struct ITestInvoker { virtual void invoke () const = 0; virtual ~ITestInvoker(); }; 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 isThrowSafe( TestCase const& testCase, IConfig const& config ); 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 ); } // end catch_interfaces_testcase.h // start catch_stringref.h #include #include #include #include namespace Catch { /// A non-owning string class (similar to the forthcoming std::string_view) /// Note that, because a StringRef may be a substring of another string, /// it may not be null terminated. class StringRef { public: using size_type = std::size_t; using const_iterator = const char*; private: static constexpr char const* const s_empty = ""; char const* m_start = s_empty; size_type m_size = 0; public: // construction constexpr StringRef() noexcept = default; StringRef( char const* rawChars ) noexcept; constexpr StringRef( char const* rawChars, size_type size ) noexcept : m_start( rawChars ), m_size( size ) {} StringRef( std::string const& stdString ) noexcept : m_start( stdString.c_str() ), m_size( stdString.size() ) {} explicit operator std::string() const { return std::string(m_start, m_size); } public: // operators auto operator == ( StringRef const& other ) const noexcept -> bool; auto operator != (StringRef const& other) const noexcept -> bool { return !(*this == other); } auto operator[] ( size_type index ) const noexcept -> char { assert(index < m_size); return m_start[index]; } public: // named queries constexpr auto empty() const noexcept -> bool { return m_size == 0; } constexpr auto size() const noexcept -> size_type { return m_size; } // Returns the current start pointer. If the StringRef is not // null-terminated, throws std::domain_exception auto c_str() const -> char const*; public: // substrings and searches // Returns a substring of [start, start + length). // If start + length > size(), then the substring is [start, size()). // If start > size(), then the substring is empty. auto substr( size_type start, size_type length ) const noexcept -> StringRef; // Returns the current start pointer. May not be null-terminated. auto data() const noexcept -> char const*; constexpr auto isNullTerminated() const noexcept -> bool { return m_start[m_size] == '\0'; } public: // iterators constexpr const_iterator begin() const { return m_start; } constexpr const_iterator end() const { return m_start + m_size; } }; auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { return StringRef( rawChars, size ); } } // namespace Catch constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { return Catch::StringRef( rawChars, size ); } // end catch_stringref.h // start catch_preprocessor.hpp #define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ #define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) #ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ // MSVC needs more evaluations #define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) #else #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) #endif #define CATCH_REC_END(...) #define CATCH_REC_OUT #define CATCH_EMPTY() #define CATCH_DEFER(id) id CATCH_EMPTY() #define CATCH_REC_GET_END2() 0, CATCH_REC_END #define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 #define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 #define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT #define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) #define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) #define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) #define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) #define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) #define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) #define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) #define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) // Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, // and passes userdata as the first parameter to each invocation, // e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) #define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) #define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) #define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) #define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ #define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ #define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF #define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) #else // MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF #define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) #define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) #endif #define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ #define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) #define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) #define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) #else #define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) #define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) #endif #define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) #define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) #define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) #define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) #define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) #define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) #define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) #define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) #define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) #define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) #define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) #define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) #define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N #define INTERNAL_CATCH_TYPE_GEN\ template struct TypeList {};\ template\ constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ template class...> struct TemplateTypeList{};\ template class...Cs>\ constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ template\ struct append;\ template\ struct rewrap;\ template class, typename...>\ struct create;\ template class, typename>\ struct convert;\ \ template \ struct append { using type = T; };\ template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ template< template class L1, typename...E1, typename...Rest>\ struct append, TypeList, Rest...> { using type = L1; };\ \ template< template class Container, template class List, typename...elems>\ struct rewrap, List> { using type = TypeList>; };\ template< template class Container, template class List, class...Elems, typename...Elements>\ struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ \ template