summaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/pathutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/pathutil.cpp')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/pathutil.cpp171
1 files changed, 145 insertions, 26 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp
index 314eab85..99be003c 100644
--- a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp
@@ -20,6 +20,9 @@
20 20
21#define PATH_GOOD_ENOUGH 64 21#define PATH_GOOD_ENOUGH 64
22 22
23static BOOL IsPathSeparatorChar(
24 __in WCHAR wc
25 );
23static BOOL IsValidDriveChar( 26static BOOL IsValidDriveChar(
24 __in WCHAR wc 27 __in WCHAR wc
25 ); 28 );
@@ -41,7 +44,7 @@ DAPI_(LPWSTR) PathFile(
41 // \ => Windows path 44 // \ => Windows path
42 // / => unix and URL path 45 // / => unix and URL path
43 // : => relative path from mapped root 46 // : => relative path from mapped root
44 if (L'\\' == *wz || L'/' == *wz || (L':' == *wz && wz == wzPath + 1)) 47 if (IsPathSeparatorChar(*wz) || (L':' == *wz && wz == wzPath + 1))
45 { 48 {
46 wzFile = wz + 1; 49 wzFile = wz + 1;
47 } 50 }
@@ -64,7 +67,7 @@ DAPI_(LPCWSTR) PathExtension(
64 LPCWSTR wzExtension = NULL; 67 LPCWSTR wzExtension = NULL;
65 for (LPCWSTR wz = wzPath; *wz; ++wz) 68 for (LPCWSTR wz = wzPath; *wz; ++wz)
66 { 69 {
67 if (L'\\' == *wz || L'/' == *wz || L':' == *wz) 70 if (IsPathSeparatorChar(*wz) || L':' == *wz)
68 { 71 {
69 wzExtension = NULL; 72 wzExtension = NULL;
70 } 73 }
@@ -84,7 +87,8 @@ DAPI_(HRESULT) PathGetDirectory(
84 ) 87 )
85{ 88{
86 HRESULT hr = S_OK; 89 HRESULT hr = S_OK;
87 size_t cchDirectory = SIZE_T_MAX; 90 LPCWSTR wzRemaining = NULL;
91 SIZE_T cchDirectory = 0;
88 92
89 for (LPCWSTR wz = wzPath; *wz; ++wz) 93 for (LPCWSTR wz = wzPath; *wz; ++wz)
90 { 94 {
@@ -92,18 +96,20 @@ DAPI_(HRESULT) PathGetDirectory(
92 // \ => Windows path 96 // \ => Windows path
93 // / => unix and URL path 97 // / => unix and URL path
94 // : => relative path from mapped root 98 // : => relative path from mapped root
95 if (L'\\' == *wz || L'/' == *wz || (L':' == *wz && wz == wzPath + 1)) 99 if (IsPathSeparatorChar(*wz) || (L':' == *wz && wz == wzPath + 1))
96 { 100 {
97 cchDirectory = static_cast<size_t>(wz - wzPath) + 1; 101 wzRemaining = wz;
98 } 102 }
99 } 103 }
100 104
101 if (SIZE_T_MAX == cchDirectory) 105 if (!wzRemaining)
102 { 106 {
103 // we were given just a file name, so there's no directory available 107 // we were given just a file name, so there's no directory available
104 return S_FALSE; 108 ExitFunction1(hr = S_FALSE);
105 } 109 }
106 110
111 cchDirectory = static_cast<SIZE_T>(wzRemaining - wzPath) + 1;
112
107 hr = StrAllocString(psczDirectory, wzPath, cchDirectory); 113 hr = StrAllocString(psczDirectory, wzPath, cchDirectory);
108 PathExitOnFailure(hr, "Failed to copy directory."); 114 PathExitOnFailure(hr, "Failed to copy directory.");
109 115
@@ -122,7 +128,7 @@ DAPI_(HRESULT) PathGetParentPath(
122 128
123 for (LPCWSTR wz = wzPath; *wz; ++wz) 129 for (LPCWSTR wz = wzPath; *wz; ++wz)
124 { 130 {
125 if (wz[1] && (L'\\' == *wz || L'/' == *wz)) 131 if (IsPathSeparatorChar(*wz) && wz[1])
126 { 132 {
127 wzParent = wz; 133 wzParent = wz;
128 } 134 }
@@ -291,12 +297,13 @@ DAPI_(HRESULT) PathPrefix(
291 hr = StrAllocPrefix(psczFullPath, L"\\\\?\\", 4); 297 hr = StrAllocPrefix(psczFullPath, L"\\\\?\\", 4);
292 PathExitOnFailure(hr, "Failed to add prefix to file path."); 298 PathExitOnFailure(hr, "Failed to add prefix to file path.");
293 } 299 }
294 else if (fFullyQualified && L'\\' == wzFullPath[1]) // UNC 300 else if (fFullyQualified && IsPathSeparatorChar(wzFullPath[1])) // UNC
295 { 301 {
296 hr = StrSize(*psczFullPath, &cbFullPath); 302 hr = StrSize(*psczFullPath, &cbFullPath);
297 PathExitOnFailure(hr, "Failed to get size of full path."); 303 PathExitOnFailure(hr, "Failed to get size of full path.");
298 304
299 memmove_s(wzFullPath, cbFullPath, wzFullPath + 1, cbFullPath - sizeof(WCHAR)); 305 memmove_s(wzFullPath, cbFullPath, wzFullPath + 1, cbFullPath - sizeof(WCHAR));
306 wzFullPath[0] = L'\\';
300 307
301 hr = StrAllocPrefix(psczFullPath, L"\\\\?\\UNC", 7); 308 hr = StrAllocPrefix(psczFullPath, L"\\\\?\\UNC", 7);
302 PathExitOnFailure(hr, "Failed to add prefix to UNC path."); 309 PathExitOnFailure(hr, "Failed to add prefix to UNC path.");
@@ -312,6 +319,90 @@ LExit:
312} 319}
313 320
314 321
322DAPI_(HRESULT) PathFixedNormalizeSlashes(
323 __inout_z LPWSTR wzPath
324 )
325{
326 HRESULT hr = S_OK;
327 size_t cchLength = 0;
328 BOOL fAllowDoubleSlash = FALSE;
329 SIZE_T iSource = 0;
330 SIZE_T jDestination = 0;
331
332 hr = ::StringCchLengthW(wzPath, STRSAFE_MAX_CCH, &cchLength);
333 PathExitOnFailure(hr, "Failed to get length of path.");
334
335 if (1 < cchLength && IsPathSeparatorChar(wzPath[0]))
336 {
337 if (IsPathSeparatorChar(wzPath[1]))
338 {
339 // \\?\\a\ is not equivalent to \\?\a\ and \\server\\a\ is not equivalent to \\server\a\.
340 fAllowDoubleSlash = TRUE;
341 wzPath[0] = '\\';
342 wzPath[1] = '\\';
343 iSource = 2;
344 jDestination = 2;
345 }
346 else if (2 < cchLength && L'?' == wzPath[1] && L'?' == wzPath[2])
347 {
348 // \??\\a\ is not equivalent to \??\a\.
349 fAllowDoubleSlash = TRUE;
350 wzPath[0] = '\\';
351 wzPath[1] = '?';
352 wzPath[2] = '?';
353 iSource = 3;
354 jDestination = 3;
355 }
356 }
357
358 for (; iSource < cchLength; ++iSource)
359 {
360 if (IsPathSeparatorChar(wzPath[iSource]))
361 {
362 if (fAllowDoubleSlash)
363 {
364 fAllowDoubleSlash = FALSE;
365 }
366 else if (IsPathSeparatorChar(wzPath[iSource + 1]))
367 {
368 // Skip consecutive slashes.
369 continue;
370 }
371
372 wzPath[jDestination] = '\\';
373 }
374 else
375 {
376 wzPath[jDestination] = wzPath[iSource];
377 }
378
379 ++jDestination;
380 }
381
382 for (; jDestination < cchLength; ++jDestination)
383 {
384 wzPath[jDestination] = '\0';
385 }
386
387LExit:
388 return hr;
389}
390
391
392DAPI_(void) PathFixedReplaceForwardSlashes(
393 __inout_z LPWSTR wzPath
394 )
395{
396 for (LPWSTR wz = wzPath; *wz; ++wz)
397 {
398 if (L'/' == *wz)
399 {
400 *wz = L'\\';
401 }
402 }
403}
404
405
315DAPI_(HRESULT) PathFixedBackslashTerminate( 406DAPI_(HRESULT) PathFixedBackslashTerminate(
316 __inout_ecount_z(cchPath) LPWSTR wzPath, 407 __inout_ecount_z(cchPath) LPWSTR wzPath,
317 __in SIZE_T cchPath 408 __in SIZE_T cchPath
@@ -320,17 +411,28 @@ DAPI_(HRESULT) PathFixedBackslashTerminate(
320 HRESULT hr = S_OK; 411 HRESULT hr = S_OK;
321 size_t cchLength = 0; 412 size_t cchLength = 0;
322 413
414 if (!cchPath)
415 {
416 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
417 }
418
323 hr = ::StringCchLengthW(wzPath, cchPath, &cchLength); 419 hr = ::StringCchLengthW(wzPath, cchPath, &cchLength);
324 PathExitOnFailure(hr, "Failed to get length of path."); 420 PathExitOnFailure(hr, "Failed to get length of path.");
325 421
326 if (cchLength >= cchPath) 422 LPWSTR wzLast = wzPath + (cchLength - 1);
423 if (cchLength && L'/' == wzLast[0])
327 { 424 {
328 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); 425 wzLast[0] = L'\\';
329 } 426 }
330 else if (L'\\' != wzPath[cchLength - 1]) 427 else if (!cchLength || L'\\' != wzLast[0])
331 { 428 {
332 wzPath[cchLength] = L'\\'; 429 if (cchLength + 2 > cchPath)
333 wzPath[cchLength + 1] = L'\0'; 430 {
431 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
432 }
433
434 wzLast[1] = L'\\';
435 wzLast[2] = L'\0';
334 } 436 }
335 437
336LExit: 438LExit:
@@ -339,10 +441,10 @@ LExit:
339 441
340 442
341DAPI_(HRESULT) PathBackslashTerminate( 443DAPI_(HRESULT) PathBackslashTerminate(
342 __inout LPWSTR* psczPath 444 __inout_z LPWSTR* psczPath
343 ) 445 )
344{ 446{
345 Assert(psczPath && *psczPath); 447 Assert(psczPath);
346 448
347 HRESULT hr = S_OK; 449 HRESULT hr = S_OK;
348 SIZE_T cchPath = 0; 450 SIZE_T cchPath = 0;
@@ -354,7 +456,12 @@ DAPI_(HRESULT) PathBackslashTerminate(
354 hr = ::StringCchLengthW(*psczPath, cchPath, &cchLength); 456 hr = ::StringCchLengthW(*psczPath, cchPath, &cchLength);
355 PathExitOnFailure(hr, "Failed to get length of path."); 457 PathExitOnFailure(hr, "Failed to get length of path.");
356 458
357 if (L'\\' != (*psczPath)[cchLength - 1]) 459 LPWSTR wzLast = *psczPath + (cchLength - 1);
460 if (cchLength && L'/' == wzLast[0])
461 {
462 wzLast[0] = L'\\';
463 }
464 else if (!cchLength || L'\\' != wzLast[0])
358 { 465 {
359 hr = StrAllocConcat(psczPath, L"\\", 1); 466 hr = StrAllocConcat(psczPath, L"\\", 1);
360 PathExitOnFailure(hr, "Failed to concat backslash onto string."); 467 PathExitOnFailure(hr, "Failed to concat backslash onto string.");
@@ -833,13 +940,13 @@ DAPI_(BOOL) PathIsFullyQualified(
833 ExitFunction(); 940 ExitFunction();
834 } 941 }
835 942
836 if (L'\\' != wzPath[0]) 943 if (!IsPathSeparatorChar(wzPath[0]))
837 { 944 {
838 // The only way to specify a fully qualified path that doesn't begin with a slash 945 // The only way to specify a fully qualified path that doesn't begin with a slash
839 // is the drive, colon, slash format (C:\). 946 // is the drive, colon, slash format (C:\).
840 if (IsValidDriveChar(wzPath[0]) && 947 if (IsValidDriveChar(wzPath[0]) &&
841 L':' == wzPath[1] && 948 L':' == wzPath[1] &&
842 L'\\' == wzPath[2]) 949 IsPathSeparatorChar(wzPath[2]))
843 { 950 {
844 fFullyQualified = TRUE; 951 fFullyQualified = TRUE;
845 } 952 }
@@ -849,14 +956,14 @@ DAPI_(BOOL) PathIsFullyQualified(
849 956
850 // Non-drive fully qualified paths must start with \\ or \?. 957 // Non-drive fully qualified paths must start with \\ or \?.
851 // \??\ is an archaic form of \\?\. 958 // \??\ is an archaic form of \\?\.
852 if (L'?' != wzPath[1] && L'\\' != wzPath[1]) 959 if (L'?' != wzPath[1] && !IsPathSeparatorChar(wzPath[1]))
853 { 960 {
854 ExitFunction(); 961 ExitFunction();
855 } 962 }
856 963
857 fFullyQualified = TRUE; 964 fFullyQualified = TRUE;
858 965
859 if (L'?' == wzPath[2] && L'\\' == wzPath[3]) 966 if (L'?' == wzPath[2] && IsPathSeparatorChar(wzPath[3]))
860 { 967 {
861 fHasLongPathPrefix = TRUE; 968 fHasLongPathPrefix = TRUE;
862 } 969 }
@@ -877,7 +984,7 @@ DAPI_(BOOL) PathIsRooted(
877 ) 984 )
878{ 985{
879 return wzPath && 986 return wzPath &&
880 (wzPath[0] == L'\\' || 987 (IsPathSeparatorChar(wzPath[0]) ||
881 IsValidDriveChar(wzPath[0]) && wzPath[1] == L':'); 988 IsValidDriveChar(wzPath[0]) && wzPath[1] == L':');
882} 989}
883 990
@@ -1008,20 +1115,25 @@ DAPI_(HRESULT) PathGetHierarchyArray(
1008 1115
1009 for (size_t i = 0; i < cchPath; ++i) 1116 for (size_t i = 0; i < cchPath; ++i)
1010 { 1117 {
1011 if (wzPath[i] == L'\\') 1118 if (IsPathSeparatorChar(wzPath[i]))
1012 { 1119 {
1013 ++cArraySpacesNeeded; 1120 ++cArraySpacesNeeded;
1014 } 1121 }
1015 } 1122 }
1016 1123
1017 if (wzPath[cchPath - 1] != L'\\') 1124 if (!IsPathSeparatorChar(wzPath[cchPath - 1]))
1018 { 1125 {
1019 ++cArraySpacesNeeded; 1126 ++cArraySpacesNeeded;
1020 } 1127 }
1021 1128
1022 // If it's a UNC path, cut off the first three paths, 2 because it starts with a double backslash, and another because the first ("\\servername\") isn't a path. 1129 // If it's a UNC path, cut off the first three paths, 2 because it starts with a double backslash, and another because the first ("\\servername\") isn't a path.
1023 if (wzPath[0] == L'\\' && wzPath[1] == L'\\') 1130 if (IsPathSeparatorChar(wzPath[0]) && IsPathSeparatorChar(wzPath[1]))
1024 { 1131 {
1132 if (3 > cArraySpacesNeeded)
1133 {
1134 ExitFunction1(hr = E_INVALIDARG);
1135 }
1136
1025 cArraySpacesNeeded -= 3; 1137 cArraySpacesNeeded -= 3;
1026 } 1138 }
1027 1139
@@ -1042,7 +1154,7 @@ DAPI_(HRESULT) PathGetHierarchyArray(
1042 DWORD cchPathCopy = lstrlenW(sczPathCopy); 1154 DWORD cchPathCopy = lstrlenW(sczPathCopy);
1043 1155
1044 // If it ends in a backslash, it's a directory path, so cut off everything the last backslash before we get the directory portion of the path 1156 // If it ends in a backslash, it's a directory path, so cut off everything the last backslash before we get the directory portion of the path
1045 if (wzPath[cchPathCopy - 1] == L'\\') 1157 if (IsPathSeparatorChar(wzPath[cchPathCopy - 1]))
1046 { 1158 {
1047 sczPathCopy[cchPathCopy - 1] = L'\0'; 1159 sczPathCopy[cchPathCopy - 1] = L'\0';
1048 } 1160 }
@@ -1063,6 +1175,13 @@ LExit:
1063 return hr; 1175 return hr;
1064} 1176}
1065 1177
1178static BOOL IsPathSeparatorChar(
1179 __in WCHAR wc
1180 )
1181{
1182 return L'/' == wc || L'\\' == wc;
1183}
1184
1066static BOOL IsValidDriveChar( 1185static BOOL IsValidDriveChar(
1067 __in WCHAR wc 1186 __in WCHAR wc
1068 ) 1187 )