aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/serd/serd.h16
-rw-r--r--src/node.c47
-rw-r--r--test/.clang-tidy4
-rw-r--r--test/test_uri.c26
4 files changed, 92 insertions, 1 deletions
diff --git a/include/serd/serd.h b/include/serd/serd.h
index a2e767ff..dd165360 100644
--- a/include/serd/serd.h
+++ b/include/serd/serd.h
@@ -674,6 +674,22 @@ SerdNode* SERD_ALLOCATED
serd_new_boolean(bool b);
/**
+ Create a new file URI node for a file that exists on this system.
+
+ This is like serd_new_file_uri() except it resolves and canonicalizes the
+ path, so the returned node is always a complete file URI with a scheme and
+ absolute path that does not contain any dot references or links, or NULL if
+ this is impossible (for example, because the path does not exist).
+
+ This should be used wherever the URI for an existent file is required, for
+ example to set the base URI of a document.
+*/
+SERD_API
+SerdNode* SERD_ALLOCATED
+serd_new_real_file_uri(const char* SERD_NULLABLE path,
+ const char* SERD_NULLABLE hostname);
+
+/**
Create a new node by serialising `d` into an xsd:decimal string
The resulting node will always contain a `.', start with a digit, and end
diff --git a/src/node.c b/src/node.c
index 566e8839..76c12235 100644
--- a/src/node.c
+++ b/src/node.c
@@ -14,6 +14,8 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#define _XOPEN_SOURCE 600 /* for realpath */
+
#include "node.h"
#include "namespaces.h"
@@ -24,6 +26,11 @@
#include "exess/exess.h"
#include "serd/serd.h"
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN 1
+# include <windows.h>
+#endif
+
#include <assert.h>
#include <float.h>
#include <math.h>
@@ -539,6 +546,32 @@ is_uri_path_char(const char c)
}
}
+static char*
+serd_realpath(const char* const path)
+{
+ if (!path) {
+ return NULL;
+ }
+
+#ifdef _WIN32
+ const DWORD size = GetFullPathName(path, 0, NULL, NULL);
+ if (size == 0) {
+ return NULL;
+ }
+
+ char* const out = (char*)calloc(size, 1);
+ const DWORD ret = GetFullPathName(path, MAX_PATH, out, NULL);
+ if (ret == 0 || ret >= size) {
+ free(out);
+ return NULL;
+ }
+
+ return out;
+#else
+ return realpath(path, NULL);
+#endif
+}
+
SerdNode*
serd_new_file_uri(const SerdStringView path, const SerdStringView hostname)
{
@@ -586,6 +619,20 @@ serd_new_file_uri(const SerdStringView path, const SerdStringView hostname)
return node;
}
+SerdNode*
+serd_new_real_file_uri(const char* const path, const char* const hostname)
+{
+ char* const real_path = serd_realpath(path);
+ if (!real_path) {
+ return NULL;
+ }
+
+ SerdNode* const node = serd_new_file_uri(SERD_MEASURE_STRING(real_path),
+ SERD_MEASURE_STRING(hostname));
+ free(real_path);
+ return node;
+}
+
typedef size_t (*SerdWriteLiteralFunc)(const void* const user_data,
const size_t buf_size,
char* const buf);
diff --git a/test/.clang-tidy b/test/.clang-tidy
index de654d8d..b7dd752b 100644
--- a/test/.clang-tidy
+++ b/test/.clang-tidy
@@ -3,6 +3,10 @@ Checks: >
-*-magic-numbers,
-*-uppercase-literal-suffix,
-android-cloexec-fopen,
+ -bugprone-reserved-identifier,
+ -bugprone-suspicious-string-compare,
+ -cert-dcl37-c,
+ -cert-dcl51-cpp,
-clang-analyzer-nullability.NullabilityBase,
-clang-analyzer-nullability.NullableDereferenced,
-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,
diff --git a/test/test_uri.c b/test/test_uri.c
index 88aa342c..dff4d999 100644
--- a/test/test_uri.c
+++ b/test/test_uri.c
@@ -20,6 +20,11 @@
#include "serd/serd.h"
+#if defined(_WIN32) && !defined(__MINGW32__)
+# include <io.h>
+# define mkstemp(pat) _mktemp(pat)
+#endif
+
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
@@ -80,6 +85,24 @@ test_uri_parsing(void)
}
static void
+test_real_file_uri(void)
+{
+ char path[16];
+ strncpy(path, "serd_XXXXXX", sizeof(path));
+ assert(mkstemp(path) > 0);
+
+ SerdNode* const good = serd_new_real_file_uri(path, NULL);
+ assert(good);
+ assert(!strncmp(serd_node_string(good), "file://", 7));
+ serd_node_free(good);
+
+ SerdNode* const bad = serd_new_real_file_uri("not_a_file", NULL);
+ assert(!bad);
+
+ assert(!remove(path));
+}
+
+static void
test_parse_uri(void)
{
const SerdStringView base = SERD_STATIC_STRING("http://example.org/a/b/c/");
@@ -204,7 +227,7 @@ test_uri_resolution(void)
const SerdURIView rel_foo_uri = serd_relative_uri(abs_foo_uri, base_uri);
const SerdURIView resolved_uri = serd_resolve_uri(rel_foo_uri, base_uri);
-SerdNode* const resolved = serd_new_parsed_uri(resolved_uri);
+ SerdNode* const resolved = serd_new_parsed_uri(resolved_uri);
assert(!strcmp(serd_node_string(resolved), "http://example.org/a/b/c/foo"));
serd_node_free(resolved);
@@ -215,6 +238,7 @@ main(void)
{
test_uri_parsing();
test_parse_uri();
+ test_real_file_uri();
test_is_within();
test_relative_uri();
test_uri_resolution();