diff options
-rw-r--r-- | src/serd_internal.h | 44 | ||||
-rw-r--r-- | tests/serd_test.c | 9 |
2 files changed, 39 insertions, 14 deletions
diff --git a/src/serd_internal.h b/src/serd_internal.h index 04f9feaa..18cc74bd 100644 --- a/src/serd_internal.h +++ b/src/serd_internal.h @@ -431,36 +431,52 @@ uri_path_at(const SerdURI* uri, size_t i) } } -/** Return true iff `uri` shares path components with `root` */ -static inline bool -uri_is_related(const SerdURI* uri, const SerdURI* root) +/** + Return the index of the first differing character after the last root slash, + or zero if `uri` is not under `root`. +*/ +static inline size_t +uri_rooted_index(const SerdURI* uri, const SerdURI* root) { if (!root || !root->scheme.len || !chunk_equals(&root->scheme, &uri->scheme) || !chunk_equals(&root->authority, &uri->authority)) { - return false; + return 0; } - bool differ = false; - const size_t path_len = uri_path_len(uri); - const size_t root_len = uri_path_len(root); + bool differ = false; + const size_t path_len = uri_path_len(uri); + const size_t root_len = uri_path_len(root); + size_t last_root_slash = 0; for (size_t i = 0; i < path_len && i < root_len; ++i) { - if (uri_path_at(uri, i) != uri_path_at(root, i)) { - differ = true; - } - if (differ && uri_path_at(root, i) == '/') { - return false; + const uint8_t u = uri_path_at(uri, i); + const uint8_t r = uri_path_at(root, i); + + differ = differ || u != r; + if (r == '/') { + last_root_slash = i; + if (differ) { + return 0; + } } } - return true; + return last_root_slash + 1; +} + +/** Return true iff `uri` shares path components with `root` */ +static inline bool +uri_is_related(const SerdURI* uri, const SerdURI* root) +{ + return uri_rooted_index(uri, root) > 0; } /** Return true iff `uri` is within the base of `root` */ static inline bool uri_is_under(const SerdURI* uri, const SerdURI* root) { - return uri->path.len >= root->path.len && uri_is_related(uri, root); + const size_t index = uri_rooted_index(uri, root); + return index > 0 && uri->path.len > index; } static inline bool diff --git a/tests/serd_test.c b/tests/serd_test.c index a987b153..e312ad04 100644 --- a/tests/serd_test.c +++ b/tests/serd_test.c @@ -422,6 +422,15 @@ main(void) FAILF("Bad relative URI %s (expected 'http://example.org/')\n", noup.buf); } + SerdNode x = serd_node_from_string(SERD_URI, USTR("http://example.org/foo/x")); + SerdURI x_uri; + serd_uri_parse(x.buf, &x_uri); + + SerdNode x_rel = serd_node_new_relative_uri(&x_uri, &abs_uri, &abs_uri, NULL); + if (strcmp((const char*)x_rel.buf, "x")) { + FAILF("Bad relative URI %s (expected 'x')\n", x_rel.buf); + } + serd_node_free(&noup); serd_node_free(&up); serd_node_free(&rel); |