|
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