aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS3
-rw-r--r--src/node.c20
-rw-r--r--test/test_uri.c56
3 files changed, 69 insertions, 10 deletions
diff --git a/NEWS b/NEWS
index 474f38f9..bb69bdf9 100644
--- a/NEWS
+++ b/NEWS
@@ -1,11 +1,12 @@
serd (0.30.17) unstable; urgency=medium
+ * Add Windows path separator support to serd_node_new_file_uri()
* Fix crash when trying to read chunks without starting
* Fix hang when skipping an error at EOF when lax parsing
* Override pkg-config dependency within meson
* Test header for warnings more strictly
- -- David Robillard <d@drobilla.net> Mon, 24 Oct 2022 02:07:19 +0000
+ -- David Robillard <d@drobilla.net> Mon, 14 Nov 2022 21:06:21 +0000
serd (0.30.16) stable; urgency=medium
diff --git a/src/node.c b/src/node.c
index f3c28cea..3da5726c 100644
--- a/src/node.c
+++ b/src/node.c
@@ -170,6 +170,16 @@ is_uri_path_char(const uint8_t c)
}
}
+static bool
+is_dir_sep(const char c)
+{
+ #ifdef _WIN32
+ return c == '\\' || c == '/';
+ #else
+ return c == '/';
+ #endif
+}
+
SerdNode
serd_node_new_file_uri(const uint8_t* const path,
const uint8_t* const hostname,
@@ -182,7 +192,7 @@ serd_node_new_file_uri(const uint8_t* const path,
size_t uri_len = 0;
uint8_t* uri = NULL;
- if (path[0] == '/' || is_windows) {
+ if (is_dir_sep(path[0]) || is_windows) {
uri_len = strlen("file://") + hostname_len + is_windows;
uri = (uint8_t*)calloc(uri_len + 1, 1);
@@ -199,12 +209,14 @@ serd_node_new_file_uri(const uint8_t* const path,
SerdChunk chunk = {uri, uri_len};
for (size_t i = 0; i < path_len; ++i) {
- if (is_windows && path[i] == '\\') {
- serd_chunk_sink("/", 1, &chunk);
- } else if (path[i] == '%') {
+ if (path[i] == '%') {
serd_chunk_sink("%%", 2, &chunk);
} else if (!escape || is_uri_path_char(path[i])) {
serd_chunk_sink(path + i, 1, &chunk);
+#ifdef _WIN32
+ } else if (path[i] == '\\') {
+ serd_chunk_sink("/", 1, &chunk);
+#endif
} else {
char escape_str[4] = {'%', 0, 0, 0};
snprintf(escape_str + 1, sizeof(escape_str) - 1, "%X", (unsigned)path[i]);
diff --git a/test/test_uri.c b/test/test_uri.c
index c79e618d..ea66d0f1 100644
--- a/test/test_uri.c
+++ b/test/test_uri.c
@@ -81,17 +81,63 @@ static void
test_uri_parsing(void)
{
test_file_uri(NULL, "C:/My 100%", true, "file:///C:/My%20100%%", NULL);
- test_file_uri("ahost",
- "C:\\Pointless Space",
- true,
- "file://ahost/C:/Pointless%20Space",
- "C:/Pointless Space");
test_file_uri(NULL, "/foo/bar", true, "file:///foo/bar", NULL);
test_file_uri("bhost", "/foo/bar", true, "file://bhost/foo/bar", NULL);
test_file_uri(NULL, "a/relative path", false, "a/relative path", NULL);
test_file_uri(
NULL, "a/relative <path>", true, "a/relative%20%3Cpath%3E", NULL);
+#ifdef _WIN32
+ test_file_uri(
+ NULL, "C:\\My 100%", true, "file:///C:/My%20100%%", "C:/My 100%");
+
+ test_file_uri(NULL,
+ "\\drive\\relative",
+ true,
+ "file:///drive/relative",
+ "/drive/relative");
+
+ test_file_uri(NULL,
+ "C:\\Program Files\\Serd",
+ true,
+ "file:///C:/Program%20Files/Serd",
+ "C:/Program Files/Serd");
+
+ test_file_uri("ahost",
+ "C:\\Pointless Space",
+ true,
+ "file://ahost/C:/Pointless%20Space",
+ "C:/Pointless Space");
+#else
+ /* What happens with Windows paths on other platforms is a bit weird, but
+ more or less unavoidable. It doesn't work to interpret backslashes as
+ path separators on any other platform. */
+
+ test_file_uri("ahost",
+ "C:\\Pointless Space",
+ true,
+ "file://ahost/C:%5CPointless%20Space",
+ "/C:\\Pointless Space");
+
+ test_file_uri(NULL,
+ "\\drive\\relative",
+ true,
+ "%5Cdrive%5Crelative",
+ "\\drive\\relative");
+
+ test_file_uri(NULL,
+ "C:\\Program Files\\Serd",
+ true,
+ "file:///C:%5CProgram%20Files%5CSerd",
+ "/C:\\Program Files\\Serd");
+
+ test_file_uri("ahost",
+ "C:\\Pointless Space",
+ true,
+ "file://ahost/C:%5CPointless%20Space",
+ "/C:\\Pointless Space");
+#endif
+
// Test tolerance of parsing junk URI escapes
uint8_t* out_path = serd_file_uri_parse(USTR("file:///foo/%0Xbar"), NULL);