aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2021-02-28 14:24:24 -0500
committerDavid Robillard <d@drobilla.net>2021-03-08 23:23:06 -0500
commitd9ea0564d0954967788b688a224cf81f7892c4a7 (patch)
treed43e38888e5dd14d0439f76ea57017bf6e954be9
parent8f1192bb2361fcd7907b926e86c41a171ed04ad0 (diff)
downloadserd-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.h16
-rw-r--r--src/node.c30
-rw-r--r--src/uri.c38
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
diff --git a/src/node.c b/src/node.c
index 76c12235..0448c312 100644
--- a/src/node.c
+++ b/src/node.c
@@ -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;
diff --git a/src/uri.c b/src/uri.c
index 6b029284..5b1ed598 100644
--- a/src/uri.c
+++ b/src/uri.c
@@ -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)