[Git][debian-gis-team/libosmium][upstream] New upstream version 2.23.1

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Wed Apr 1 17:01:03 BST 2026



Bas Couwenberg pushed to branch upstream at Debian GIS Project / libosmium


Commits:
5792f527 by Bas Couwenberg at 2026-04-01T17:53:52+02:00
New upstream version 2.23.1
- - - - -


15 changed files:

- .github/workflows/ci.yml
- .github/workflows/clang-tidy.yml
- CHANGELOG.md
- CMakeLists.txt
- README.md
- include/osmium/handler/check_order.hpp
- include/osmium/io/detail/pbf_input_format.hpp
- include/osmium/io/detail/string_util.hpp
- include/osmium/io/detail/xml_output_format.hpp
- include/osmium/osm/object_comparisons.hpp
- include/osmium/version.hpp
- test/t/handler/test_check_order_handler.cpp
- test/t/io/test_output_utils.cpp
- test/t/io/test_pbf.cpp
- test/t/osm/test_object_comparisons.cpp


Changes:

=====================================
.github/workflows/ci.yml
=====================================
@@ -119,7 +119,7 @@ jobs:
             rubygem-json \
             spatialite-tools \
             zlib-devel
-      - uses: actions/checkout at v4
+      - uses: actions/checkout at v6
         with:
           submodules: true
       - uses: ./.github/actions/install-protozero
@@ -136,7 +136,7 @@ jobs:
       CXXFLAGS: -Werror
       BUILD_TYPE: Dev
     steps:
-      - uses: actions/checkout at v4
+      - uses: actions/checkout at v6
         with:
           submodules: true
       - uses: ./.github/actions/install-ubuntu
@@ -164,7 +164,7 @@ jobs:
       CXXFLAGS: -Werror
       BUILD_TYPE: ${{ matrix.build_type }}
     steps:
-      - uses: actions/checkout at v4
+      - uses: actions/checkout at v6
         with:
           submodules: true
       - uses: ./.github/actions/install-macos
@@ -183,7 +183,7 @@ jobs:
           - windows-2022
           - windows-2025
     steps:
-      - uses: actions/checkout at v4
+      - uses: actions/checkout at v6
         with:
           submodules: true
       - uses: ./.github/actions/install-windows
@@ -196,7 +196,7 @@ jobs:
     timeout-minutes: 120
     runs-on: windows-2025
     steps:
-      - uses: actions/checkout at v4
+      - uses: actions/checkout at v6
         with:
           submodules: true
       - uses: ./.github/actions/install-windows


=====================================
.github/workflows/clang-tidy.yml
=====================================
@@ -22,7 +22,7 @@ jobs:
         BUILD_TYPE: Dev
         CC: clang-${{ matrix.clang }}
         CXX: clang++-${{ matrix.clang }}
-        CPP_VERSION: c++14
+        CPP_VERSION: 14
         APT_LISTCHANGES_FRONTEND: none
         DEBIAN_FRONTEND: noninteractive
     steps:
@@ -43,7 +43,7 @@ jobs:
             make \
             zlib1g-dev
         shell: bash
-      - uses: actions/checkout at v4
+      - uses: actions/checkout at v6
         with:
           submodules: true
       - uses: ./.github/actions/install-protozero
@@ -53,7 +53,7 @@ jobs:
         shell: bash
         working-directory: build
       - name: Upload clang-tidy log
-        uses: actions/upload-artifact at v4
+        uses: actions/upload-artifact at v6
         if: always()
         with:
           name: libosmium-${{ github.sha }}-clang-tidy-${{ matrix.clang }}-log


=====================================
CHANGELOG.md
=====================================
@@ -13,6 +13,21 @@ This project adheres to [Semantic Versioning](https://semver.org/).
 ### Fixed
 
 
+## [2.23.1] - 2026-04-01
+
+### Added
+
+* Helper function for checking string for invalid UTF-8 characters.
+
+### Changed
+
+* Extend CheckOrder handler class: Optionally work with history files.
+
+### Fixed
+
+* Reverted change in 2.21.0: Order deleted objects after visible ones in
+  reverse id order. Turns out this breaks updating of extracts.
+
 ## [2.23.0] - 2026-01-18
 
 ### Added
@@ -1346,7 +1361,8 @@ long time. These will not be part of the next version of libosmium:
   Doxygen (up to version 1.8.8). This version contains a workaround to fix
   this.
 
-[unreleased]: https://github.com/osmcode/libosmium/compare/v2.23.0...HEAD
+[unreleased]: https://github.com/osmcode/libosmium/compare/v2.23.1...HEAD
+[2.23.1]: https://github.com/osmcode/libosmium/compare/v2.23.0...v2.23.1
 [2.23.0]: https://github.com/osmcode/libosmium/compare/v2.22.0...v2.23.0
 [2.22.0]: https://github.com/osmcode/libosmium/compare/v2.21.0...v2.22.0
 [2.21.0]: https://github.com/osmcode/libosmium/compare/v2.20.0...v2.21.0


=====================================
CMakeLists.txt
=====================================
@@ -55,7 +55,7 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev;Cover
 #
 #-----------------------------------------------------------------------------
 
-project(libosmium VERSION 2.23.0 LANGUAGES CXX C)
+project(libosmium VERSION 2.23.1 LANGUAGES CXX C)
 
 set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
 


=====================================
README.md
=====================================
@@ -4,7 +4,8 @@ https://osmcode.org/libosmium
 
 A fast and flexible C++ library for working with OpenStreetMap data.
 
-Libosmium works on Linux, macOS and Windows.
+Libosmium works on Linux, macOS and Windows. You need a 64bit system, 32bit
+systems are not supported.
 
 [![Build Status](https://github.com/osmcode/libosmium/actions/workflows/ci.yml/badge.svg)](https://github.com/osmcode/libosmium/actions)
 [![Packaging status](https://repology.org/badge/tiny-repos/libosmium.svg)](https://repology.org/metapackage/libosmium)


=====================================
include/osmium/handler/check_order.hpp
=====================================
@@ -76,8 +76,11 @@ namespace osmium {
          * IDs are ordered first then positive IDs, both ordered by absolute
          * value.
          *
-         * IDs have to be unique for each type. This check will fail for
-         * history files.
+         * Constructor has a single bool parameter. If this is false (default)
+         * the check is done for normal OSM data files, i.e. IDs have to be
+         * unique for each type. If this is true, the check is done for OSM
+         * history files, the combination ID/version has to be unique and the
+         * versions need to be in order.
          *
          * To use this, add a CheckOrder member variable to your handler and
          * call the node(), way(), and relation() methods from your node(),
@@ -89,12 +92,17 @@ namespace osmium {
             osmium::object_id_type m_max_node_id = 0;
             osmium::object_id_type m_max_way_id = 0;
             osmium::object_id_type m_max_relation_id = 0;
+            osmium::object_version_type m_last_version = 0;
             bool m_has_node = false;
             bool m_has_way = false;
             bool m_has_relation = false;
+            bool m_with_history;
 
         public:
 
+            CheckOrder(bool with_history = false) : m_with_history(with_history) {
+            }
+
             void node(const osmium::Node& node) {
                 if (m_has_way) {
                     throw out_of_order_error{"Found a node after a way.", node.id()};
@@ -105,7 +113,13 @@ namespace osmium {
 
                 if (m_has_node) {
                     if (m_max_node_id == node.id()) {
-                        throw out_of_order_error{"Node ID twice in input. Maybe you are using a history or change file?", node.id()};
+                        if (m_with_history) {
+                            if (node.version() <= m_last_version) {
+                                throw out_of_order_error{"Versions out of order", node.id()};
+                            }
+                        } else {
+                            throw out_of_order_error{"Node ID twice in input. Maybe you are using a history or change file?", node.id()};
+                        }
                     }
                     if (id_order{}(node.id(), m_max_node_id)) {
                         throw out_of_order_error{"Node IDs out of order: " + std::to_string(node.id()), node.id()};
@@ -115,6 +129,10 @@ namespace osmium {
                     m_max_node_id = node.id();
                     m_has_node = true;
                 }
+
+                if (m_with_history) {
+                    m_last_version = node.version();
+                }
             }
 
             void way(const osmium::Way& way) {
@@ -124,7 +142,13 @@ namespace osmium {
 
                 if (m_has_way) {
                     if (m_max_way_id == way.id()) {
-                        throw out_of_order_error{"Way ID twice in input. Maybe you are using a history or change file?", way.id()};
+                        if (m_with_history) {
+                            if (way.version() <= m_last_version) {
+                                throw out_of_order_error{"Versions out of order", way.id()};
+                            }
+                        } else {
+                            throw out_of_order_error{"Way ID twice in input. Maybe you are using a history or change file?", way.id()};
+                        }
                     }
                     if (id_order{}(way.id(), m_max_way_id)) {
                         throw out_of_order_error{"Way IDs out of order: " + std::to_string(way.id()), way.id()};
@@ -134,12 +158,22 @@ namespace osmium {
                     m_max_way_id = way.id();
                     m_has_way = true;
                 }
+
+                if (m_with_history) {
+                    m_last_version = way.version();
+                }
             }
 
             void relation(const osmium::Relation& relation) {
                 if (m_has_relation) {
                     if (m_max_relation_id == relation.id()) {
-                        throw out_of_order_error{"Relation ID twice in input. Maybe you are using a history or change file?", relation.id()};
+                        if (m_with_history) {
+                            if (relation.version() <= m_last_version) {
+                                throw out_of_order_error{"Versions out of order", relation.id()};
+                            }
+                        } else {
+                            throw out_of_order_error{"Relation ID twice in input. Maybe you are using a history or change file?", relation.id()};
+                        }
                     }
                     if (id_order{}(relation.id(), m_max_relation_id)) {
                         throw out_of_order_error{"Relation IDs out of order: " + std::to_string(relation.id()), relation.id()};
@@ -149,6 +183,10 @@ namespace osmium {
                     m_max_relation_id = relation.id();
                     m_has_relation = true;
                 }
+
+                if (m_with_history) {
+                    m_last_version = relation.version();
+                }
             }
 
             osmium::object_id_type max_node_id() const noexcept {


=====================================
include/osmium/io/detail/pbf_input_format.hpp
=====================================
@@ -100,13 +100,6 @@ namespace osmium {
                     m_input_buffer.erase(0, size);
                 }
 
-                static uint32_t get_size_in_network_byte_order(const char* d) noexcept {
-                    return (static_cast<uint32_t>(d[3])) |
-                           (static_cast<uint32_t>(d[2]) <<  8U) |
-                           (static_cast<uint32_t>(d[1]) << 16U) |
-                           (static_cast<uint32_t>(d[0]) << 24U);
-                }
-
                 static uint32_t check_size(uint32_t size) {
                     if (size > static_cast<uint32_t>(max_blob_header_size)) {
                         throw osmium::pbf_error{"invalid BlobHeader size (> max_blob_header_size)"};
@@ -256,6 +249,13 @@ namespace osmium {
 
             public:
 
+                static uint32_t get_size_in_network_byte_order(const char* d) noexcept {
+                    return (static_cast<uint32_t>(static_cast<uint8_t>(d[3]))) |
+                           (static_cast<uint32_t>(static_cast<uint8_t>(d[2])) <<  8U) |
+                           (static_cast<uint32_t>(static_cast<uint8_t>(d[1])) << 16U) |
+                           (static_cast<uint32_t>(static_cast<uint8_t>(d[0])) << 24U);
+                }
+
                 explicit PBFParser(parser_arguments& args) :
                     Parser(args),
                     m_offset_ptr(args.offset_ptr),


=====================================
include/osmium/io/detail/string_util.hpp
=====================================
@@ -142,6 +142,52 @@ namespace osmium {
                 return 0;
             }
 
+            /**
+             * Check that a string contains only valid UTF-8. Returns nullptr
+             * if the string is valid, otherwise it returns a pointer to the
+             * first invalid character.
+             *
+             * Based on https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c
+             * License: http://www.cl.cam.ac.uk/~mgk25/short-license.html
+             */
+            inline char const* utf8_check(char const* str) noexcept {
+                auto* s = reinterpret_cast<unsigned char const*>(str);
+                while (*s) {
+                    if (*s < 0x80) {
+                        /* 0xxxxxxx */
+                        s++;
+                    } else if ((s[0] & 0xe0) == 0xc0) {
+                        /* 110XXXXx 10xxxxxx */
+                        if ((s[1] & 0xc0) != 0x80 || (s[0] & 0xfe) == 0xc0) /* overlong? */ {
+                            return reinterpret_cast<char const *>(s);
+                        }
+                        s += 2;
+                    } else if ((s[0] & 0xf0) == 0xe0) {
+                        /* 1110XXXX 10Xxxxxx 10xxxxxx */
+                        if ((s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 ||
+                            (s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || /* overlong? */
+                            (s[0] == 0xed && (s[1] & 0xe0) == 0xa0) || /* surrogate? */
+                            (s[0] == 0xef && s[1] == 0xbf &&
+                            (s[2] & 0xfe) == 0xbe)) /* U+FFFE or U+FFFF? */ {
+                            return reinterpret_cast<char const *>(s);
+                        }
+                        s += 3;
+                    } else if ((s[0] & 0xf8) == 0xf0) {
+                        /* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */
+                        if ((s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 ||
+                            (s[3] & 0xc0) != 0x80 ||
+                            (s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) ||    /* overlong? */
+                            (s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) /* > U+10FFFF? */ {
+                            return reinterpret_cast<char const *>(s);
+                        }
+                        s += 4;
+                    } else {
+                        return reinterpret_cast<char const *>(s);
+                    }
+                }
+                return nullptr;
+            }
+
             inline uint32_t next_utf8_codepoint(char const** begin, const char* end) {
                 const auto* it = reinterpret_cast<const uint8_t*>(*begin);
                 uint32_t cp = 0xffU & *it;


=====================================
include/osmium/io/detail/xml_output_format.hpp
=====================================
@@ -109,7 +109,7 @@ namespace osmium {
             class XMLOutputBlock : public OutputBlock {
 
                 // operation (create, modify, delete) for osc files
-                enum class operation {
+                enum class operation : std::uint8_t {
                     op_none   = 0,
                     op_create = 1,
                     op_modify = 2,
@@ -243,6 +243,15 @@ namespace osmium {
                     m_last_op = op;
                 }
 
+                static operation get_operation(const osmium::OSMObject &object) noexcept {
+                    if (object.deleted()) {
+                        return operation::op_delete;
+                    }
+
+                    return object.version() == 1 ? operation::op_create
+                                                 : operation::op_modify;
+                }
+
             public:
 
                 XMLOutputBlock(osmium::memory::Buffer&& buffer, const xml_output_options& options) :
@@ -266,7 +275,7 @@ namespace osmium {
 
                 void node(const osmium::Node& node) {
                     if (m_options.use_change_ops) {
-                        open_close_op_tag(node.visible() ? (node.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
+                        open_close_op_tag(get_operation(node));
                     }
 
                     write_prefix();
@@ -293,7 +302,7 @@ namespace osmium {
 
                 void way(const osmium::Way& way) {
                     if (m_options.use_change_ops) {
-                        open_close_op_tag(way.visible() ? (way.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
+                        open_close_op_tag(get_operation(way));
                     }
 
                     write_prefix();
@@ -334,7 +343,7 @@ namespace osmium {
 
                 void relation(const osmium::Relation& relation) {
                     if (m_options.use_change_ops) {
-                        open_close_op_tag(relation.visible() ? (relation.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
+                        open_close_op_tag(get_operation(relation));
                     }
 
                     write_prefix();


=====================================
include/osmium/osm/object_comparisons.hpp
=====================================
@@ -154,17 +154,17 @@ namespace osmium {
      * (negative IDs first, then positive IDs, both in the order of their
      * absolute values), but later versions of an object are ordered before
      * earlier versions of the same object. This is useful when the last
-     * version of an object needs to be used.
+     * version of an object needs to be used. Object visibility is not taken
+     * into account, so objects with different visibilities keep their order.
      */
     struct object_order_type_id_reverse_version {
 
         bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
+            const bool tsvalid = lhs.timestamp().valid() && rhs.timestamp().valid();
             return const_tie(lhs.type(), lhs.id() > 0, lhs.positive_id(), rhs.version(),
-                        ((lhs.timestamp().valid() && rhs.timestamp().valid()) ? rhs.timestamp() : osmium::Timestamp()),
-                        rhs.visible()) <
+                        (tsvalid ? rhs.timestamp() : osmium::Timestamp())) <
                    const_tie(rhs.type(), rhs.id() > 0, rhs.positive_id(), lhs.version(),
-                        ((lhs.timestamp().valid() && rhs.timestamp().valid()) ? lhs.timestamp() : osmium::Timestamp()),
-                        lhs.visible());
+                        (tsvalid ? lhs.timestamp() : osmium::Timestamp()));
         }
 
         /// @pre lhs and rhs must not be nullptr


=====================================
include/osmium/version.hpp
=====================================
@@ -40,8 +40,8 @@ DEALINGS IN THE SOFTWARE.
 #define LIBOSMIUM_VERSION_MINOR 23
 
 // NOLINTNEXTLINE(modernize-macro-to-enum)
-#define LIBOSMIUM_VERSION_PATCH 0
+#define LIBOSMIUM_VERSION_PATCH 1
 
-#define LIBOSMIUM_VERSION_STRING "2.23.0"
+#define LIBOSMIUM_VERSION_STRING "2.23.1"
 
 #endif // OSMIUM_VERSION_HPP


=====================================
test/t/handler/test_check_order_handler.cpp
=====================================
@@ -5,7 +5,7 @@
 #include <osmium/opl.hpp>
 #include <osmium/visitor.hpp>
 
-TEST_CASE("CheckOrder handler if everything is in order") {
+TEST_CASE("CheckOrder handler: everything is in order") {
     osmium::memory::Buffer buffer{1024};
 
     REQUIRE(osmium::opl_parse("n-126", buffer));
@@ -126,3 +126,159 @@ TEST_CASE("CheckOrder handler: Ways after relations") {
     REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
 }
 
+TEST_CASE("CheckOrder handler for history: everything is in order") {
+    osmium::memory::Buffer buffer{1024};
+
+    REQUIRE(osmium::opl_parse("n-126", buffer));
+    REQUIRE(osmium::opl_parse("n123", buffer));
+    REQUIRE(osmium::opl_parse("n124", buffer));
+    REQUIRE(osmium::opl_parse("n128", buffer));
+    REQUIRE(osmium::opl_parse("w-100", buffer));
+    REQUIRE(osmium::opl_parse("w100", buffer));
+    REQUIRE(osmium::opl_parse("w102", buffer));
+    REQUIRE(osmium::opl_parse("r-200", buffer));
+    REQUIRE(osmium::opl_parse("r100", buffer));
+
+    osmium::handler::CheckOrder handler{true};
+    osmium::apply(buffer, handler);
+    REQUIRE(handler.max_node_id()     == 128);
+    REQUIRE(handler.max_way_id()      == 102);
+    REQUIRE(handler.max_relation_id() == 100);
+}
+
+TEST_CASE("CheckOrder handler for history: versions in order") {
+    osmium::memory::Buffer buffer{1024};
+
+    REQUIRE(osmium::opl_parse("n1 v1", buffer));
+    REQUIRE(osmium::opl_parse("n1 v2", buffer));
+    REQUIRE(osmium::opl_parse("n2 v2", buffer));
+    REQUIRE(osmium::opl_parse("n3 v1", buffer));
+
+    REQUIRE(osmium::opl_parse("w1 v1", buffer));
+    REQUIRE(osmium::opl_parse("w1 v2", buffer));
+    REQUIRE(osmium::opl_parse("w2 v2", buffer));
+    REQUIRE(osmium::opl_parse("w3 v1", buffer));
+
+    REQUIRE(osmium::opl_parse("r1 v1", buffer));
+    REQUIRE(osmium::opl_parse("r1 v2", buffer));
+    REQUIRE(osmium::opl_parse("r2 v2", buffer));
+    REQUIRE(osmium::opl_parse("r3 v1", buffer));
+
+    osmium::handler::CheckOrder handler{true};
+    osmium::apply(buffer, handler);
+    REQUIRE(handler.max_node_id()     == 3);
+    REQUIRE(handler.max_way_id()      == 3);
+    REQUIRE(handler.max_relation_id() == 3);
+}
+
+TEST_CASE("CheckOrder handler for history: Nodes must be in order") {
+    osmium::memory::Buffer buffer{1024};
+
+    REQUIRE(osmium::opl_parse("n3", buffer));
+
+    SECTION("Positive ID") {
+        REQUIRE(osmium::opl_parse("n2", buffer));
+    }
+    SECTION("Negative ID") {
+        REQUIRE(osmium::opl_parse("n-2", buffer));
+    }
+
+    osmium::handler::CheckOrder handler{true};
+    REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
+}
+
+TEST_CASE("CheckOrder handler for history: Ways must be in order") {
+    osmium::memory::Buffer buffer{1024};
+
+    REQUIRE(osmium::opl_parse("w3", buffer));
+    SECTION("Positive ID") {
+        REQUIRE(osmium::opl_parse("w2", buffer));
+    }
+    SECTION("Negative ID") {
+        REQUIRE(osmium::opl_parse("w-2", buffer));
+    }
+
+    osmium::handler::CheckOrder handler{true};
+    REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
+}
+
+TEST_CASE("CheckOrder handler for history: Relations must be in order") {
+    osmium::memory::Buffer buffer{1024};
+
+    REQUIRE(osmium::opl_parse("r3", buffer));
+    SECTION("Positive ID") {
+        REQUIRE(osmium::opl_parse("r2", buffer));
+    }
+    SECTION("Negative ID") {
+        REQUIRE(osmium::opl_parse("r-2", buffer));
+    }
+
+    osmium::handler::CheckOrder handler{true};
+    REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
+}
+
+TEST_CASE("CheckOrder handler for history: Same id/version twice is not allowed") {
+    osmium::memory::Buffer buffer{1024};
+
+    REQUIRE(osmium::opl_parse("n3 v1", buffer));
+    REQUIRE(osmium::opl_parse("n3 v1", buffer));
+
+    osmium::handler::CheckOrder handler{true};
+    REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
+}
+
+TEST_CASE("CheckOrder handler for history: Versions must be ordered") {
+    osmium::memory::Buffer buffer{1024};
+
+    REQUIRE(osmium::opl_parse("n3 v2", buffer));
+    REQUIRE(osmium::opl_parse("n3 v1", buffer));
+
+    osmium::handler::CheckOrder handler{true};
+    REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
+}
+
+TEST_CASE("CheckOrder handler for history: Nodes after ways") {
+    osmium::memory::Buffer buffer{1024};
+
+    REQUIRE(osmium::opl_parse("w50", buffer));
+    SECTION("Positive ID") {
+        REQUIRE(osmium::opl_parse("n30", buffer));
+    }
+    SECTION("Negative ID") {
+        REQUIRE(osmium::opl_parse("n-30", buffer));
+    }
+
+    osmium::handler::CheckOrder handler{true};
+    REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
+}
+
+TEST_CASE("CheckOrder handler for history: Nodes after relations") {
+    osmium::memory::Buffer buffer{1024};
+
+    REQUIRE(osmium::opl_parse("r50", buffer));
+    SECTION("Positive ID") {
+        REQUIRE(osmium::opl_parse("n30", buffer));
+    }
+    SECTION("Negative ID") {
+        REQUIRE(osmium::opl_parse("n-30", buffer));
+    }
+
+    osmium::handler::CheckOrder handler{true};
+    REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
+}
+
+TEST_CASE("CheckOrder handler for history: Ways after relations") {
+    osmium::memory::Buffer buffer{1024};
+
+    REQUIRE(osmium::opl_parse("r50", buffer));
+    SECTION("Positive ID") {
+        REQUIRE(osmium::opl_parse("w30", buffer));
+    }
+    SECTION("Negative ID") {
+        REQUIRE(osmium::opl_parse("w-30", buffer));
+    }
+
+    osmium::handler::CheckOrder handler{true};
+    REQUIRE_THROWS_AS(osmium::apply(buffer, handler), osmium::out_of_order_error);
+}
+


=====================================
test/t/io/test_output_utils.cpp
=====================================
@@ -231,3 +231,23 @@ TEST_CASE("incomplete Unicode codepoint") {
     }
 }
 
+TEST_CASE("utf-8 check for valid UTF-8") {
+    REQUIRE(osmium::io::detail::utf8_check("") == nullptr);
+    REQUIRE(osmium::io::detail::utf8_check("a") == nullptr);
+    REQUIRE(osmium::io::detail::utf8_check("abc") == nullptr);
+
+    const char* s = u8cast(u8"\n_\u01a2_\u30dc_\U0001d11e_\U0001f680");
+    REQUIRE(osmium::io::detail::utf8_check(s) == nullptr);
+}
+
+TEST_CASE("utf-8 check for illegal value") {
+    const char* s = "abc\xff";
+    REQUIRE(osmium::io::detail::utf8_check(s) != nullptr);
+}
+
+TEST_CASE("utf-8 check for incomplete Unicode codepoint") {
+    std::string s{u8cast(u8"\U0001f680")}; // rocket
+    s.resize(s.size() - 1);
+    REQUIRE(osmium::io::detail::utf8_check(s.c_str()) != nullptr);
+}
+


=====================================
test/t/io/test_pbf.cpp
=====================================
@@ -2,10 +2,13 @@
 
 #include "utils.hpp"
 
+#include <osmium/io/detail/pbf_input_format.hpp>
 #include <osmium/io/pbf_input.hpp>
 #include <osmium/io/reader.hpp>
 #include <osmium/osm/object.hpp>
 
+#include <array>
+
 TEST_CASE("Get supported PBF compression types") {
     const auto types = osmium::io::supported_pbf_compression_types();
     REQUIRE(types.size() >= 2);
@@ -50,3 +53,17 @@ TEST_CASE("Read PBF file with version=-1 and changeset=-1 and DenseNodes (writte
     REQUIRE(object.version() == 0);
     REQUIRE(object.changeset() == 0);
 }
+
+TEST_CASE("get size in network byte order") {
+    const std::array<char, 4> data1 = { 0, 0, 0, 1 };
+    REQUIRE(osmium::io::detail::PBFParser::get_size_in_network_byte_order(data1.data()) == 1);
+
+    const std::array<char, 4> data127 = { 0, 0, 0, 127 };
+    REQUIRE(osmium::io::detail::PBFParser::get_size_in_network_byte_order(data127.data()) == 127);
+
+    const std::array<char, 4> data128 = { 0, 0, 0, static_cast<char>(128) };
+    REQUIRE(osmium::io::detail::PBFParser::get_size_in_network_byte_order(data128.data()) == 128);
+
+    const std::array<char, 4> data65535 = { 0, 0, static_cast<char>(255), static_cast<char>(255) };
+    REQUIRE(osmium::io::detail::PBFParser::get_size_in_network_byte_order(data65535.data()) == 65535);
+}


=====================================
test/t/osm/test_object_comparisons.cpp
=====================================
@@ -195,11 +195,18 @@ TEST_CASE("Node comparisons") {
         REQUIRE(std::is_sorted(nodes.cbegin(), nodes.cend(), osmium::object_order_type_id_reverse_version{}));
     }
 
-    SECTION("reverse version ordering should order objects with deleted flag last") {
+    SECTION("reverse version ordering should keep order for deleted objects") {
         nodes.emplace_back(buffer.get<osmium::Node>(osmium::builder::add_node(buffer, _id( 1), _version(2), _timestamp("2016-01-01T00:00:00Z"), _deleted(false))));
         nodes.emplace_back(buffer.get<osmium::Node>(osmium::builder::add_node(buffer, _id( 1), _version(2), _timestamp("2016-01-01T00:00:00Z"), _deleted(true))));
 
         REQUIRE(std::is_sorted(nodes.cbegin(), nodes.cend(), osmium::object_order_type_id_reverse_version{}));
+
+        nodes.clear();
+
+        nodes.emplace_back(buffer.get<osmium::Node>(osmium::builder::add_node(buffer, _id( 1), _version(2), _timestamp("2016-01-01T00:00:00Z"), _deleted(true))));
+        nodes.emplace_back(buffer.get<osmium::Node>(osmium::builder::add_node(buffer, _id( 1), _version(2), _timestamp("2016-01-01T00:00:00Z"), _deleted(false))));
+
+        REQUIRE(std::is_sorted(nodes.cbegin(), nodes.cend(), osmium::object_order_type_id_reverse_version{}));
     }
 }
 



View it on GitLab: https://salsa.debian.org/debian-gis-team/libosmium/-/commit/5792f5271a05b30fa4f5d9f5a7907d42b149fe40

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/libosmium/-/commit/5792f5271a05b30fa4f5d9f5a7907d42b149fe40
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20260401/6bde0566/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list