Commit 2017a15d6ca7f756dcf036499a02e15393609c83

nulltoken 2011-12-27T16:03:28

path: add git_path_fromurl()

diff --git a/src/path.c b/src/path.c
index bd62a3e..53f0f3d 100644
--- a/src/path.c
+++ b/src/path.c
@@ -272,3 +272,38 @@ append:
 
 	return error;
 }
+
+int git_path_fromurl(git_buf *local_path_out, const char *file_url)
+{
+	int error = GIT_SUCCESS, offset = 0, len;
+
+	assert(local_path_out && file_url);
+
+	if (git__prefixcmp(file_url, "file://") != 0)
+		return git__throw(GIT_EINVALIDPATH, "Parsing of '%s' failed. A file Uri is expected (ie. with 'file://' scheme).", file_url);
+
+	offset += 7;
+	len = strlen(file_url);
+
+	if (offset < len && file_url[offset] == '/')
+		offset++;
+	else if (offset < len && git__prefixcmp(file_url + offset, "localhost/") == 0)
+		offset += 10;
+	else
+		return git__throw(GIT_EINVALIDPATH, "Parsing of '%s' failed. A local file Uri is expected.", file_url);
+
+	if (offset >= len || file_url[offset] == '/')
+		return git__throw(GIT_EINVALIDPATH, "Parsing of '%s' failed. Invalid file Uri format.", file_url);
+
+#ifndef _MSC_VER
+	offset--;	/* A *nix absolute path starts with a forward slash */
+#endif
+
+	git_buf_clear(local_path_out);
+
+	error = git__percent_decode(local_path_out, file_url + offset);
+	if (error < GIT_SUCCESS)
+		return git__rethrow(error, "Parsing of '%s' failed.", file_url);
+
+	return error;
+}
diff --git a/src/path.h b/src/path.h
index 6397fee..c308c5b 100644
--- a/src/path.h
+++ b/src/path.h
@@ -75,5 +75,6 @@ GIT_INLINE(void) git_path_mkposix(char *path)
 #endif
 
 extern int git__percent_decode(git_buf *decoded_out, const char *input);
+extern int git_path_fromurl(git_buf *local_path_out, const char *file_url);
 
 #endif
diff --git a/tests-clay/clay.h b/tests-clay/clay.h
index b2b31be..8cbd8dd 100644
--- a/tests-clay/clay.h
+++ b/tests-clay/clay.h
@@ -109,14 +109,15 @@ extern void test_core_filebuf__5(void);
 extern void test_core_hex__fromhex(void);
 extern void test_core_oid__initialize(void);
 extern void test_core_oid__streq(void);
-extern void test_core_path__0_dirname(void);
-extern void test_core_path__1_basename(void);
-extern void test_core_path__2_topdir(void);
-extern void test_core_path__5_joins(void);
-extern void test_core_path__6_long_joins(void);
-extern void test_core_path__7_path_to_dir(void);
-extern void test_core_path__8_self_join(void);
-extern void test_core_path__9_percent_decode(void);
+extern void test_core_path__00_dirname(void);
+extern void test_core_path__01_basename(void);
+extern void test_core_path__02_topdir(void);
+extern void test_core_path__05_joins(void);
+extern void test_core_path__06_long_joins(void);
+extern void test_core_path__07_path_to_dir(void);
+extern void test_core_path__08_self_join(void);
+extern void test_core_path__09_percent_decode(void);
+extern void test_core_path__10_fromurl(void);
 extern void test_core_rmdir__delete_recursive(void);
 extern void test_core_rmdir__fail_to_delete_non_empty_dir(void);
 extern void test_core_rmdir__initialize(void);
diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c
index e6bb804..ce2ffaf 100644
--- a/tests-clay/clay_main.c
+++ b/tests-clay/clay_main.c
@@ -174,14 +174,15 @@ static const struct clay_func _clay_cb_core_oid[] = {
     {"streq", &test_core_oid__streq}
 };
 static const struct clay_func _clay_cb_core_path[] = {
-    {"0_dirname", &test_core_path__0_dirname},
-	{"1_basename", &test_core_path__1_basename},
-	{"2_topdir", &test_core_path__2_topdir},
-	{"5_joins", &test_core_path__5_joins},
-	{"6_long_joins", &test_core_path__6_long_joins},
-	{"7_path_to_dir", &test_core_path__7_path_to_dir},
-	{"8_self_join", &test_core_path__8_self_join},
-	{"9_percent_decode", &test_core_path__9_percent_decode}
+    {"00_dirname", &test_core_path__00_dirname},
+	{"01_basename", &test_core_path__01_basename},
+	{"02_topdir", &test_core_path__02_topdir},
+	{"05_joins", &test_core_path__05_joins},
+	{"06_long_joins", &test_core_path__06_long_joins},
+	{"07_path_to_dir", &test_core_path__07_path_to_dir},
+	{"08_self_join", &test_core_path__08_self_join},
+	{"09_percent_decode", &test_core_path__09_percent_decode},
+	{"10_fromurl", &test_core_path__10_fromurl}
 };
 static const struct clay_func _clay_cb_core_rmdir[] = {
     {"delete_recursive", &test_core_rmdir__delete_recursive},
@@ -382,7 +383,7 @@ static const struct clay_suite _clay_suites[] = {
         "core::path",
         {NULL, NULL},
         {NULL, NULL},
-        _clay_cb_core_path, 8
+        _clay_cb_core_path, 9
     },
 	{
         "core::rmdir",
@@ -549,7 +550,7 @@ static const struct clay_suite _clay_suites[] = {
 };
 
 static size_t _clay_suite_count = 39;
-static size_t _clay_callback_count = 124;
+static size_t _clay_callback_count = 125;
 
 /* Core test functions */
 static void
diff --git a/tests-clay/core/path.c b/tests-clay/core/path.c
index 8744247..bdebfb9 100644
--- a/tests-clay/core/path.c
+++ b/tests-clay/core/path.c
@@ -70,7 +70,7 @@ check_joinpath_n(
 
 
 /* get the dirname of a path */
-void test_core_path__0_dirname(void)
+void test_core_path__00_dirname(void)
 {
 	check_dirname(NULL, ".");
 	check_dirname("", ".");
@@ -90,7 +90,7 @@ void test_core_path__0_dirname(void)
 }
 
 /* get the base name of a path */
-void test_core_path__1_basename(void)
+void test_core_path__01_basename(void)
 {
 	check_basename(NULL, ".");
 	check_basename("", ".");
@@ -107,7 +107,7 @@ void test_core_path__1_basename(void)
 }
 
 /* get the latest component in a path */
-void test_core_path__2_topdir(void)
+void test_core_path__02_topdir(void)
 {
 	check_topdir(".git/", ".git/");
 	check_topdir("/.git/", ".git/");
@@ -124,7 +124,7 @@ void test_core_path__2_topdir(void)
 }
 
 /* properly join path components */
-void test_core_path__5_joins(void)
+void test_core_path__05_joins(void)
 {
 	check_joinpath("", "", "");
 	check_joinpath("", "a", "a");
@@ -159,7 +159,7 @@ void test_core_path__5_joins(void)
 }
 
 /* properly join path components for more than one path */
-void test_core_path__6_long_joins(void)
+void test_core_path__06_long_joins(void)
 {
 	check_joinpath_n("", "", "", "", "");
 	check_joinpath_n("", "a", "", "", "a/");
@@ -212,7 +212,7 @@ check_string_to_dir(
 }
 
 /* convert paths to dirs */
-void test_core_path__7_path_to_dir(void)
+void test_core_path__07_path_to_dir(void)
 {
 	check_path_to_dir("", "");
 	check_path_to_dir(".", "./");
@@ -240,7 +240,7 @@ void test_core_path__7_path_to_dir(void)
 }
 
 /* join path to itself */
-void test_core_path__8_self_join(void)
+void test_core_path__08_self_join(void)
 {
 	git_buf path = GIT_BUF_INIT;
 	ssize_t asize = 0;
@@ -284,7 +284,7 @@ static void check_percent_decoding(const char *expected_result, const char *inpu
 	git_buf_free(&buf);
 }
 
-void test_core_path__9_percent_decode(void)
+void test_core_path__09_percent_decode(void)
 {
 	check_percent_decoding("abcd", "abcd");
 	check_percent_decoding("a2%", "a2%");
@@ -297,3 +297,42 @@ void test_core_path__9_percent_decode(void)
 	check_percent_decoding("a bc ", "a%20bc%20");
 	check_percent_decoding("Vicent Mart" "\355", "Vicent%20Mart%ED");
 }
+
+static void check_fromurl(const char *expected_result, const char *input, int should_fail)
+{
+	git_buf buf = GIT_BUF_INIT;
+
+	assert(should_fail || expected_result);
+
+	if (!should_fail) {
+		cl_git_pass(git_path_fromurl(&buf, input));
+		cl_assert_strequal(expected_result, git_buf_cstr(&buf));
+	} else
+		cl_git_fail(git_path_fromurl(&buf, input));
+
+	git_buf_free(&buf);
+}
+
+#ifdef _MSC_VER
+#define ABS_PATH_MARKER ""
+#else
+#define ABS_PATH_MARKER "/"
+#endif
+
+void test_core_path__10_fromurl(void)
+{
+	/* Failing cases */
+	check_fromurl(NULL, "a", 1);
+	check_fromurl(NULL, "http:///c:/Temp%20folder/note.txt", 1);
+	check_fromurl(NULL, "file://c:/Temp%20folder/note.txt", 1);
+	check_fromurl(NULL, "file:////c:/Temp%20folder/note.txt", 1);
+	check_fromurl(NULL, "file:///", 1);
+	check_fromurl(NULL, "file:////", 1);
+	check_fromurl(NULL, "file://servername/c:/Temp%20folder/note.txt", 1);
+
+	/* Passing cases */
+	check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file:///c:/Temp%20folder/note.txt", 0);
+	check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file://localhost/c:/Temp%20folder/note.txt", 0);
+	check_fromurl(ABS_PATH_MARKER "c:/Temp+folder/note.txt", "file:///c:/Temp+folder/note.txt", 0);
+	check_fromurl(ABS_PATH_MARKER "a", "file:///a", 0);
+}