Skip to content

Commit 990c791

Browse files
authored
Merge pull request #2227 from compnerd/separation-is-never-easy
CoreFoundation: correct CreateStringFromFileSystemRepresentationByAdd…
2 parents 73a8350 + 365fe8b commit 990c791

File tree

2 files changed

+88
-6
lines changed

2 files changed

+88
-6
lines changed

CoreFoundation/URL.subproj/CFURL.c

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -894,15 +894,34 @@ static CFStringRef CreateStringFromFileSystemRepresentationByAddingPercentEscape
894894
if ( idx == numBytes ) {
895895
if ( isDirectory ) {
896896
// if it is a directory and it doesn't end with PATH_SEP, append a PATH_SEP.
897-
if ( bytes[numBytes-1] != '/' ) {
898-
*bufBytePtr++ = '/';
897+
if ( windowsPath ) {
898+
if ( bufBytePtr - bufStartPtr > 3 ) {
899+
if ( strncmp((const char *)(bufBytePtr - 3), "%2F", 3) ) {
900+
*bufBytePtr++ = '%';
901+
*bufBytePtr++ = '2';
902+
*bufBytePtr++ = 'F';
903+
}
904+
}
905+
}
906+
else {
907+
if ( bytes[numBytes-1] != '/' ) {
908+
*bufBytePtr++ = '/';
909+
}
899910
}
900911
}
901912
else {
902913
// it is not a directory: remove any pathDelim characters at end (leaving at least one character)
903-
while ( (numBytes > 1) && (bytes[numBytes-1] == '/') ) {
904-
--bufBytePtr;
905-
--numBytes;
914+
if ( windowsPath ) {
915+
while ( (numBytes > 1) && (bufBytePtr - bufStartPtr > 3) && (strncmp((const char *)(bufBytePtr - 3), "%2F", 3) == 0) ) {
916+
bufBytePtr -= 3;
917+
--numBytes;
918+
}
919+
}
920+
else {
921+
while ( (numBytes > 1) && (bytes[numBytes-1] == '/') ) {
922+
--bufBytePtr;
923+
--numBytes;
924+
}
906925
}
907926
}
908927

TestFoundation/TestURL.swift

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,60 @@ private func getTestData() -> [Any]? {
4747
}
4848

4949
class TestURL : XCTestCase {
50+
#if os(Windows)
51+
func test_WindowsPathSeparator() {
52+
// ensure that the mixed slashes are handled properly
53+
// e.g. NOT file:///S:/b/u1%2/
54+
let u1 = URL(fileURLWithPath: "S:\\b\\u1/")
55+
XCTAssertEqual(u1.absoluteString, "file:///S:/b/u1/")
56+
57+
// ensure that trailing slashes are compressed
58+
// e.g. NOT file:///S:/b/u2%2F%2F%2F%/
59+
let u2 = URL(fileURLWithPath: "S:\\b\\u2/////")
60+
XCTAssertEqual(u2.absoluteString, "file:///S:/b/u2/")
61+
62+
// ensure that the trailing slashes are compressed even when mixed
63+
// e.g. NOT file:///S:/b/u3%2F%/%2F%2/
64+
let u3 = URL(fileURLWithPath: "S:\\b\\u3//\\//")
65+
// XCTAssertEqual(u3.absoluteString, "file:///S:/b/u3/%2F/")
66+
XCTAssertEqual(u3.path, "S:\\b\\u3\\")
67+
68+
// ensure that the regular conversion works
69+
let u4 = URL(fileURLWithPath: "S:\\b\\u4")
70+
XCTAssertEqual(u4.absoluteString, "file:///S:/b/u4")
71+
72+
// ensure that the trailing slash is added
73+
let u5 = URL(fileURLWithPath: "S:\\b\\u5", isDirectory: true)
74+
XCTAssertEqual(u5.absoluteString, "file:///S:/b/u5/")
75+
76+
// ensure that the trailing slash is preserved
77+
let u6 = URL(fileURLWithPath: "S:\\b\\u6\\")
78+
XCTAssertEqual(u6.absoluteString, "file:///S:/b/u6/")
79+
80+
// ensure that we do not index beyond the start of the string
81+
let u7 = URL(fileURLWithPath: "eh", relativeTo: URL(fileURLWithPath: "S:\\b"))
82+
XCTAssertEqual(u7.absoluteString, "file:///S:/b/eh")
83+
84+
// ensure that / is handled properly
85+
let u8 = URL(fileURLWithPath: "/")
86+
XCTAssertEqual(u8.absoluteString, "file:///")
87+
}
88+
89+
func test_WindowsPathSeparator2() {
90+
let u1 = URL(fileURLWithPath: "S:\\b\\u1\\", isDirectory: false)
91+
XCTAssertEqual(u1.absoluteString, "file:///S:/b/u1")
92+
93+
let u2 = URL(fileURLWithPath: "/", isDirectory: false)
94+
XCTAssertEqual(u2.absoluteString, "file:///")
95+
96+
let u3 = URL(fileURLWithPath: "\\", isDirectory: false)
97+
XCTAssertEqual(u3.absoluteString, "file:///")
98+
99+
let u4 = URL(fileURLWithPath: "S:\\b\\u3//\\//")
100+
XCTAssertEqual(u4.absoluteString, "file:///S:/b/u3/")
101+
}
102+
#endif
103+
50104
func test_fileURLWithPath_relativeTo() {
51105
let homeDirectory = NSHomeDirectory()
52106
let homeURL = URL(fileURLWithPath: homeDirectory, isDirectory: true)
@@ -604,7 +658,7 @@ class TestURL : XCTestCase {
604658
}
605659

606660
static var allTests: [(String, (TestURL) -> () throws -> Void)] {
607-
return [
661+
var tests: [(String, (TestURL) -> () throws -> Void)] = [
608662
("test_URLStrings", test_URLStrings),
609663
("test_fileURLWithPath_relativeTo", test_fileURLWithPath_relativeTo ),
610664
// TODO: these tests fail on linux, more investigation is needed
@@ -619,6 +673,15 @@ class TestURL : XCTestCase {
619673
("test_URLResourceValues", testExpectedToFail(test_URLResourceValues,
620674
"test_URLResourceValues: Except for .nameKey, we have no testable attributes that work in the environment Swift CI uses, for now. SR-XXXX")),
621675
]
676+
677+
#if os(Windows)
678+
tests.append(contentsOf: [
679+
("test_WindowsPathSeparator", test_WindowsPathSeparator),
680+
("test_WindowsPathSeparator2", test_WindowsPathSeparator2),
681+
])
682+
#endif
683+
684+
return tests
622685
}
623686
}
624687

0 commit comments

Comments
 (0)