|
8 | 8 | #ifdef MS_WINDOWS
|
9 | 9 | # include <malloc.h>
|
10 | 10 | # include <windows.h>
|
11 |
| -# include <pathcch.h> // PathCchCombineEx |
| 11 | +# if defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) |
| 12 | +# define PATHCCH_ALLOW_LONG_PATHS 0x01 |
| 13 | +# else |
| 14 | +# include <pathcch.h> // PathCchCombineEx |
| 15 | +# endif |
12 | 16 | extern int winerror_to_errno(int);
|
13 | 17 | #endif
|
14 | 18 |
|
@@ -2107,123 +2111,71 @@ _Py_abspath(const wchar_t *path, wchar_t **abspath_p)
|
2107 | 2111 | #endif
|
2108 | 2112 | }
|
2109 | 2113 |
|
2110 |
| -// The Windows Games API family does not provide these functions |
2111 |
| -// so provide our own implementations. Remove them in case they get added |
2112 |
| -// to the Games API family |
2113 |
| -// Note that this implementation does not handle all the same cases as the real |
2114 |
| -// function, but we expect games are very unlikely to encounter the more obscure |
2115 |
| -// cases. |
| 2114 | +// The Windows Games API family implements the PathCch* APIs in the Xbox OS, |
| 2115 | +// but does not expose them yet. Load them dynamically until |
| 2116 | +// 1) they are officially exposed |
| 2117 | +// 2) we stop supporting older versions of the GDK which do not expose them |
2116 | 2118 | #if defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP)
|
2117 | 2119 | HRESULT
|
2118 | 2120 | PathCchSkipRoot(const wchar_t *path, const wchar_t **rootEnd)
|
2119 | 2121 | {
|
2120 |
| - if (path[0] == '\\') { |
2121 |
| - /* relative path with root e.g. \Windows */ |
2122 |
| - if (path[1] != '\\') { |
2123 |
| - *rootEnd = path + 1; |
2124 |
| - return S_OK; |
| 2122 | + static int initialized = 0; |
| 2123 | + typedef HRESULT(__stdcall *PPathCchSkipRoot) (PCWSTR pszPath, |
| 2124 | + PCWSTR *ppszRootEnd); |
| 2125 | + static PPathCchSkipRoot _PathCchSkipRoot; |
| 2126 | + |
| 2127 | + if (initialized == 0) { |
| 2128 | + HMODULE pathapi = LoadLibraryExW(L"api-ms-win-core-path-l1-1-0.dll", NULL, |
| 2129 | + LOAD_LIBRARY_SEARCH_SYSTEM32); |
| 2130 | + if (pathapi) { |
| 2131 | + _PathCchSkipRoot = (PPathCchSkipRoot)GetProcAddress( |
| 2132 | + pathapi, "PathCchSkipRoot"); |
2125 | 2133 | }
|
2126 |
| - |
2127 |
| - /* UNC drives e.g. \\server\share or \\?\UNC\server\share */ |
2128 |
| - const wchar_t *end = path + 2; |
2129 |
| - if (!wcsnicmp(end, L"?\\UNC\\", 6)) { |
2130 |
| - end += 6; |
2131 |
| - } |
2132 |
| - |
2133 |
| - end = wcschr(end, '\\'); |
2134 |
| - if (!end) { |
2135 |
| - *rootEnd = path + wcslen(path); |
2136 |
| - return S_OK; |
| 2134 | + else { |
| 2135 | + _PathCchSkipRoot = NULL; |
2137 | 2136 | }
|
2138 |
| - end = wcschr(end + 1, '\\'); |
2139 |
| - *rootEnd = (!end) ? path + wcslen(path) : end + 1; |
2140 |
| - return S_OK; |
| 2137 | + initialized = 1; |
2141 | 2138 | }
|
2142 |
| - /* absolute / relative path with drive, e.g. C: or C:\ */ |
2143 |
| - else if (isalpha(path[0]) && path[1] == ':') { |
2144 |
| - *rootEnd = (path[2] == '\\') ? path + 3 : path + 2; |
2145 |
| - return S_OK; |
2146 |
| - } |
2147 |
| - |
2148 |
| - /* relative path */ |
2149 |
| - return E_INVALIDARG; |
2150 |
| -} |
2151 | 2139 |
|
2152 |
| -static HRESULT |
2153 |
| -PathCchStripToRoot(wchar_t *path, size_t size) |
2154 |
| -{ |
2155 |
| - wchar_t *end; |
2156 |
| - if (PathCchSkipRoot(path, &end) == S_OK) { |
2157 |
| - if (*end == '\0') { |
2158 |
| - return S_FALSE; |
2159 |
| - } |
2160 |
| - *end = '\0'; |
| 2140 | + if (!_PathCchSkipRoot) { |
| 2141 | + return E_NOINTERFACE; |
2161 | 2142 | }
|
2162 | 2143 |
|
2163 |
| - return E_INVALIDARG; |
| 2144 | + return _PathCchSkipRoot(path, rootEnd); |
2164 | 2145 | }
|
2165 | 2146 |
|
2166 |
| -static wchar_t* |
2167 |
| -PathAddBackslashW(wchar_t *path) |
2168 |
| -{ |
2169 |
| - size_t len; |
2170 |
| - if (!path) { |
2171 |
| - return NULL; |
2172 |
| - } |
2173 |
| - len = wcslen(path); |
2174 |
| - if (len && path[len - 1] != '\\') { |
2175 |
| - path[len++] = '\\'; |
2176 |
| - path[len] = '\0'; |
2177 |
| - } |
2178 |
| - return path + len; |
2179 |
| -} |
2180 |
| - |
2181 |
| -#ifndef PATHCCH_ALLOW_LONG_PATHS |
2182 |
| -#define PATHCCH_ALLOW_LONG_PATHS 0x01 |
2183 |
| -#endif |
2184 |
| - |
2185 | 2147 | static HRESULT
|
2186 | 2148 | PathCchCombineEx(wchar_t *buffer, size_t bufsize, const wchar_t *dirname,
|
2187 | 2149 | const wchar_t *relfile, unsigned long flags)
|
2188 | 2150 | {
|
2189 |
| - (void)flags; |
2190 |
| - |
2191 |
| - if ((isalpha(relfile[0]) && relfile[1] == ':') || |
2192 |
| - (relfile[0] == '\\' && relfile[1] == '\\')) |
2193 |
| - { |
2194 |
| - dirname = relfile; |
2195 |
| - relfile = NULL; |
2196 |
| - } |
2197 |
| - |
2198 |
| - size_t dir_len = wcslen(dirname); |
2199 |
| - size_t file_len = relfile ? wcslen(relfile) : 0; |
2200 |
| - /* path is at max dirname + filename + backslash + \0 */ |
2201 |
| - size_t new_len = dir_len + file_len + 2; |
2202 |
| - if (new_len > bufsize) { |
2203 |
| - return E_INVALIDARG; |
2204 |
| - } |
2205 |
| - |
2206 |
| - size_t combined_length = dir_len; |
2207 |
| - wcscpy(buffer, dirname); |
2208 |
| - if (!relfile || !relfile[0]) { |
2209 |
| - if(wcsncmp(buffer, L"\\\\?\\", 4)) { |
2210 |
| - buffer += 4; |
| 2151 | + static int initialized = 0; |
| 2152 | + typedef HRESULT(__stdcall *PPathCchCombineEx) (PWSTR pszPathOut, |
| 2153 | + size_t cchPathOut, |
| 2154 | + PCWSTR pszPathIn, |
| 2155 | + PCWSTR pszMore, |
| 2156 | + unsigned long dwFlags); |
| 2157 | + static PPathCchCombineEx _PathCchCombineEx; |
| 2158 | + |
| 2159 | + if (initialized == 0) { |
| 2160 | + HMODULE pathapi = LoadLibraryExW(L"api-ms-win-core-path-l1-1-0.dll", NULL, |
| 2161 | + LOAD_LIBRARY_SEARCH_SYSTEM32); |
| 2162 | + if (pathapi) { |
| 2163 | + _PathCchCombineEx = (PPathCchCombineEx)GetProcAddress( |
| 2164 | + pathapi, "PathCchCombineEx"); |
2211 | 2165 | }
|
2212 |
| - if (isalpha(buffer[0]) && buffer[1] == ':' && !buffer[2]) { |
2213 |
| - PathAddBackslashW(buffer); |
| 2166 | + else { |
| 2167 | + _PathCchCombineEx = NULL; |
2214 | 2168 | }
|
| 2169 | + initialized = 1; |
2215 | 2170 | }
|
2216 |
| - else { |
2217 |
| - if (relfile[0] == '\\' && relfile[1] != '\\') |
2218 |
| - { |
2219 |
| - PathCchStripToRoot(buffer, combined_length); |
2220 |
| - relfile++; |
2221 |
| - } |
2222 |
| - PathAddBackslashW(buffer); |
2223 |
| - wcscat(buffer, relfile); |
| 2171 | + |
| 2172 | + if (!_PathCchCombineEx) { |
| 2173 | + return E_NOINTERFACE; |
2224 | 2174 | }
|
2225 |
| - return S_OK; |
| 2175 | + |
| 2176 | + return _PathCchCombineEx(buffer, bufsize, dirname, relfile, flags); |
2226 | 2177 | }
|
| 2178 | + |
2227 | 2179 | #endif /* defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) */
|
2228 | 2180 |
|
2229 | 2181 | // The caller must ensure "buffer" is big enough.
|
|
0 commit comments