// Copyright 2011-2023 David Robillard // SPDX-License-Identifier: ISC #ifndef SERD_SRC_URI_UTILS_H #define SERD_SRC_URI_UTILS_H #include "serd/serd.h" #include "string_utils.h" #include #include #include typedef struct { size_t shared; size_t root; } SlashIndexes; static inline bool chunk_equals(const SerdChunk* const a, const SerdChunk* const 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* const uri) { return uri->path_base.len + uri->path.len; } static inline uint8_t uri_path_at(const SerdURI* const uri, const 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 last slash shared with the root, or `SIZE_MAX`. The index of the next slash found in the root is also returned, so the two can be compared to determine if the URI is within the root (if the shared slash is the last in the root, then the URI is a child of the root, otherwise it may merely share some leading path components). */ static inline SERD_PURE_FUNC SlashIndexes uri_rooted_index(const SerdURI* const uri, const SerdURI* const root) { SlashIndexes indexes = {SIZE_MAX, SIZE_MAX}; if (!root || !root->scheme.len || !chunk_equals(&root->scheme, &uri->scheme) || !chunk_equals(&root->authority, &uri->authority)) { return indexes; } const size_t path_len = uri_path_len(uri); const size_t root_len = uri_path_len(root); const size_t min_len = path_len < root_len ? path_len : root_len; for (size_t i = 0; i < min_len; ++i) { const uint8_t u = uri_path_at(uri, i); const uint8_t r = uri_path_at(root, i); if (u == r) { if (u == '/') { indexes.root = indexes.shared = i; } } else { for (size_t j = i; j < root_len; ++j) { if (uri_path_at(root, j) == '/') { indexes.root = j; break; } } return indexes; } } return indexes; } /** Return true iff `uri` shares path components with `root` */ static inline SERD_PURE_FUNC bool uri_is_related(const SerdURI* const uri, const SerdURI* const root) { return uri_rooted_index(uri, root).shared != SIZE_MAX; } /** Return true iff `uri` is within the base of `root` */ static inline SERD_PURE_FUNC bool uri_is_under(const SerdURI* const uri, const SerdURI* const root) { const SlashIndexes indexes = uri_rooted_index(uri, root); return indexes.shared && indexes.shared != SIZE_MAX && indexes.shared == indexes.root; } static inline bool is_uri_scheme_char(const int c) { return c == '+' || c == '-' || c == '.' || c == ':' || is_alpha(c) || is_digit(c); } #endif // SERD_SRC_URI_UTILS_H