diff options
author | David Robillard <d@drobilla.net> | 2021-02-28 14:24:24 -0500 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2021-03-08 23:23:06 -0500 |
commit | d9ea0564d0954967788b688a224cf81f7892c4a7 (patch) | |
tree | d43e38888e5dd14d0439f76ea57017bf6e954be9 | |
parent | 8f1192bb2361fcd7907b926e86c41a171ed04ad0 (diff) | |
download | serd-d9ea0564d0954967788b688a224cf81f7892c4a7.tar.gz serd-d9ea0564d0954967788b688a224cf81f7892c4a7.tar.bz2 serd-d9ea0564d0954967788b688a224cf81f7892c4a7.zip |
Make serd_uri_string_length() precise and add it to public API
-rw-r--r-- | include/serd/serd.h | 16 | ||||
-rw-r--r-- | src/node.c | 30 | ||||
-rw-r--r-- | src/uri.c | 38 |
3 files changed, 61 insertions, 23 deletions
diff --git a/include/serd/serd.h b/include/serd/serd.h index dd165360..af087ab5 100644 --- a/include/serd/serd.h +++ b/include/serd/serd.h @@ -577,6 +577,18 @@ bool serd_uri_is_within(SerdURIView r, SerdURIView base); /** + Return the length of `uri` as a string. + + This can be used to get the expected number of bytes that will be written by + serd_write_uri(). + + @return A string length in bytes, not including the null terminator. +*/ +SERD_API +size_t +serd_uri_string_length(SerdURIView uri); + +/** Write `uri` as a string to `sink`. This will call `sink` several times to emit the serialised URI. @@ -584,7 +596,9 @@ serd_uri_is_within(SerdURIView r, SerdURIView base); @param uri URI to write as a string. @param sink Sink to write string output to. @param stream Opaque user argument to pass to `sink`. - @return The number of bytes written. + + @return The number of bytes written, which is less than + `serd_uri_string_length(uri)` on error. */ SERD_API size_t @@ -95,25 +95,6 @@ serd_node_check_padding(const SerdNode* node) } static size_t -serd_uri_string_length(const SerdURIView* uri) -{ - size_t len = uri->path_prefix.len; - -#define ADD_LEN(field, n_delims) \ - if ((field).len) { \ - len += (field).len + (n_delims); \ - } - - ADD_LEN(uri->path, 1) // + possible leading `/' - ADD_LEN(uri->scheme, 1) // + trailing `:' - ADD_LEN(uri->authority, 2) // + leading `//' - ADD_LEN(uri->query, 1) // + leading `?' - ADD_LEN(uri->fragment, 1) // + leading `#' - - return len + 2; // + 2 for authority `//' -} - -static size_t string_sink(const void* buf, size_t size, size_t nmemb, void* stream) { char** ptr = (char**)stream; @@ -280,7 +261,7 @@ serd_new_typed_literal_uri(const SerdStringView str, const SerdNodeFlags flags, const SerdURIView datatype_uri) { - const size_t datatype_uri_len = serd_uri_string_length(&datatype_uri); + const size_t datatype_uri_len = serd_uri_string_length(datatype_uri); const size_t len = serd_node_pad_size(str.len); const size_t total_len = len + sizeof(SerdNode) + datatype_uri_len; @@ -294,6 +275,7 @@ serd_new_typed_literal_uri(const SerdStringView str, char* ptr = serd_node_buffer(datatype_node); const size_t actual_len = serd_write_uri(datatype_uri, string_sink, &ptr); + assert(actual_len == datatype_uri_len); serd_node_buffer(datatype_node)[actual_len] = '\0'; datatype_node->n_bytes = actual_len; @@ -462,11 +444,13 @@ serd_new_uri(const SerdStringView str) SerdNode* serd_new_parsed_uri(const SerdURIView uri) { - const size_t len = serd_uri_string_length(&uri); + const size_t len = serd_uri_string_length(uri); SerdNode* const node = serd_node_malloc(len, 0, SERD_URI); char* ptr = serd_node_buffer(node); const size_t actual_len = serd_write_uri(uri, string_sink, &ptr); + assert(actual_len == len); + serd_node_buffer(node)[actual_len] = '\0'; node->n_bytes = actual_len; @@ -478,11 +462,13 @@ static SerdNode* serd_new_from_uri(const SerdURIView uri, const SerdURIView base) { const SerdURIView abs_uri = serd_resolve_uri(uri, base); - const size_t len = serd_uri_string_length(&abs_uri); + const size_t len = serd_uri_string_length(abs_uri); SerdNode* node = serd_node_malloc(len, 0, SERD_URI); char* ptr = serd_node_buffer(node); const size_t actual_len = serd_write_uri(abs_uri, string_sink, &ptr); + assert(actual_len == len); + serd_node_buffer(node)[actual_len] = '\0'; node->n_bytes = actual_len; @@ -410,6 +410,44 @@ serd_uri_is_within(const SerdURIView uri, const SerdURIView base) return true; } +size_t +serd_uri_string_length(const SerdURIView uri) +{ + size_t len = 0; + + if (uri.scheme.buf) { + len += uri.scheme.len + 1; + } + + if (uri.authority.buf) { + const bool needs_extra_slash = + (uri.authority.len > 0 && uri_path_len(&uri) > 0 && + uri_path_at(&uri, 0) != '/'); + + len += 2 + uri.authority.len + needs_extra_slash; + } + + if (uri.path_prefix.buf) { + len += uri.path_prefix.len; + } else if (uri.path_prefix.len) { + len += 3 * uri.path_prefix.len; + } + + if (uri.path.buf) { + len += uri.path.len; + } + + if (uri.query.buf) { + len += uri.query.len + 1; + } + + if (uri.fragment.buf) { + len += uri.fragment.len; + } + + return len; +} + /// See http://tools.ietf.org/html/rfc3986#section-5.3 size_t serd_write_uri(const SerdURIView uri, SerdWriteFunc sink, void* stream) |