// Copyright 2011-2020 David Robillard // SPDX-License-Identifier: ISC #ifndef SERD_URI_UTILS_H #define SERD_URI_UTILS_H #include "serd/serd.h" #include "string_utils.h" #include #include #include static inline bool chunk_equals(const SerdChunk* a, const SerdChunk* b) { return a->len == b->len && !strncmp((const char*)a->buf, (const char*)b->buf, a->len); } static inline size_t uri_path_len(const SerdURI* uri) { return uri->path_base.len + uri->path.len; } static inline uint8_t uri_path_at(const SerdURI* uri, size_t i) { return (i < uri->path_base.len) ? uri->path_base.buf[i] : uri->path.buf[i - uri->path_base.len]; } /** Return the index of the first differing character after the last root slash, or zero if `uri` is not under `root`. */ static inline SERD_PURE_FUNC 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 0; } 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) { 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 last_root_slash + 1; } /** Return true iff `uri` shares path components with `root` */ static inline SERD_PURE_FUNC 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 SERD_PURE_FUNC bool uri_is_under(const SerdURI* uri, const SerdURI* root) { const size_t index = uri_rooted_index(uri, root); return index > 0 && uri->path.len > index; } static inline bool is_uri_scheme_char(const int c) { switch (c) { case ':': case '+': case '-': case '.': return true; default: return is_alpha(c) || is_digit(c); } } #endif // SERD_URI_UTILS_H