From 8334438cb5cb9756885248a952b9feb480eebc8c Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 14 Nov 2022 10:39:05 -0500 Subject: Add Windows path separator support to serd_node_new_file_uri() --- NEWS | 3 ++- src/node.c | 20 ++++++++++++++++---- test/test_uri.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 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 Mon, 24 Oct 2022 02:07:19 +0000 + -- David Robillard 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 ", 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); -- cgit v1.2.1