diff options
-rw-r--r-- | desktop/win32/source/loader.cxx | 203 | ||||
-rw-r--r-- | desktop/win32/source/unoinfo.cxx | 9 | ||||
-rw-r--r-- | include/tools/pathutils.hxx | 20 | ||||
-rw-r--r-- | pyuno/zipcore/python.cxx | 60 | ||||
-rw-r--r-- | tools/qa/cppunit/test_pathutils.cxx | 8 | ||||
-rw-r--r-- | tools/source/misc/pathutils.cxx | 59 |
6 files changed, 141 insertions, 218 deletions
diff --git a/desktop/win32/source/loader.cxx b/desktop/win32/source/loader.cxx index bbc97a462724..b51475430911 100644 --- a/desktop/win32/source/loader.cxx +++ b/desktop/win32/source/loader.cxx @@ -33,9 +33,6 @@ #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ini_parser.hpp> -#define MY_LENGTH(s) (std::size(s) - 1) -#define MY_STRING(s) (s), MY_LENGTH(s) - namespace { void fail() @@ -85,9 +82,10 @@ std::wstring getCWDarg() { std::wstring s(L" \"-env:OOO_CWD="); - WCHAR cwd[MAX_PATH]; - DWORD cwdLen = GetCurrentDirectoryW(MAX_PATH, cwd); - if (cwdLen == 0 || cwdLen >= MAX_PATH) + DWORD cwdLen = GetCurrentDirectoryW(0, nullptr); + std::vector<WCHAR> cwd(cwdLen); + cwdLen = GetCurrentDirectoryW(cwdLen, cwd.data()); + if (cwdLen == 0 || cwdLen >= cwd.size()) { s += L'0'; } @@ -96,7 +94,7 @@ std::wstring getCWDarg() s += L'2'; size_t n = 0; // number of trailing backslashes - for (auto* p = cwd; *p; ++p) + for (auto* p = cwd.data(); *p; ++p) { WCHAR c = *p; if (c == L'$') @@ -132,26 +130,30 @@ WCHAR* commandLineAppend(WCHAR* buffer, std::wstring_view text) // Set the PATH environment variable in the current (loader) process, so that a // following CreateProcess has the necessary environment: -// @param binPath -// Must point to an array of size at least MAX_PATH. Is filled with the null -// terminated full path to the "bin" file corresponding to the current -// executable. -// @param iniDirectory -// Must point to an array of size at least MAX_PATH. Is filled with the null -// terminated full directory path (ending in "\") to the "ini" file -// corresponding to the current executable. -void extendLoaderEnvironment(WCHAR * binPath, WCHAR * iniDirectory) { - if (!GetModuleFileNameW(nullptr, iniDirectory, MAX_PATH)) { - fail(); - } - WCHAR * iniDirEnd = tools::filename(iniDirectory); - WCHAR name[MAX_PATH + MY_LENGTH(L".bin")]; - // hopefully std::size_t is large enough to not overflow - WCHAR * nameEnd = name; - for (WCHAR * p = iniDirEnd; *p != L'\0'; ++p) { - *nameEnd++ = *p; +// returns a pair of strings { binPath, iniDirectory } +// * binPath is the full path to the "bin" file corresponding to the current executable. +// * iniDirectory is the full directory path (ending in "\") to the "ini" file corresponding to the +// current executable. +[[nodiscard]] std::pair<std::wstring, std::wstring> extendLoaderEnvironment() +{ + std::vector<wchar_t> executable_path(MAX_PATH); + DWORD exe_len; + for (;;) + { + exe_len = GetModuleFileNameW(nullptr, executable_path.data(), executable_path.size()); + if (!exe_len) + fail(); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + executable_path.resize(exe_len + 4); // to accomodate a possible ".bin" in the end + break; + } + executable_path.resize(executable_path.size() * 2); } - if (!(nameEnd - name >= 4 && nameEnd[-4] == L'.' && + WCHAR* iniDirEnd = tools::filename(executable_path.data()); + std::wstring_view iniDirView(executable_path.data(), iniDirEnd); + WCHAR* nameEnd = executable_path.data() + exe_len; + if (!(nameEnd - iniDirEnd >= 4 && nameEnd[-4] == L'.' && (((nameEnd[-3] == L'E' || nameEnd[-3] == L'e') && (nameEnd[-2] == L'X' || nameEnd[-2] == L'x') && (nameEnd[-1] == L'E' || nameEnd[-1] == L'e')) || @@ -165,30 +167,30 @@ void extendLoaderEnvironment(WCHAR * binPath, WCHAR * iniDirectory) { nameEnd[-3] = 'b'; nameEnd[-2] = 'i'; nameEnd[-1] = 'n'; - tools::buildPath(binPath, iniDirectory, iniDirEnd, name, nameEnd - name); - *iniDirEnd = L'\0'; - std::size_t const maxEnv = 32767; - WCHAR env[maxEnv]; - DWORD n = GetEnvironmentVariableW(L"PATH", env, maxEnv); - if ((n >= maxEnv || n == 0) && GetLastError() != ERROR_ENVVAR_NOT_FOUND) { + std::wstring_view nameView(iniDirEnd, nameEnd); + + WCHAR env[32767]; + DWORD n = GetEnvironmentVariableW(L"PATH", env, std::size(env)); + if ((n >= std::size(env) || n == 0) && GetLastError() != ERROR_ENVVAR_NOT_FOUND) { fail(); } + std::wstring_view envView(env, n); // must be first in PATH to override other entries - assert(*(iniDirEnd - 1) == L'\\'); // hence -1 below - std::wstring_view iniDirView(iniDirectory, iniDirEnd - iniDirectory - 1); - if (!std::wstring_view(env, n).starts_with(iniDirView) || env[iniDirView.size()] != L';') + assert(iniDirView.back() == L'\\'); // hence -1 below + std::wstring_view iniDirView1(iniDirView.substr(0, iniDirView.size() - 1)); + if (!envView.starts_with(iniDirView1) || env[iniDirView1.size()] != L';') { - WCHAR pad[MAX_PATH + maxEnv]; - // hopefully std::size_t is large enough to not overflow - WCHAR* p = commandLineAppend(pad, iniDirView); + std::wstring pad(iniDirView1); if (n != 0) { - *p++ = L';'; - commandLineAppend(p, std::wstring_view(env, n)); + pad += L';'; + pad += envView; } - if (!SetEnvironmentVariableW(L"PATH", pad)) { + if (!SetEnvironmentVariableW(L"PATH", pad.data())) { fail(); } } + + return { tools::buildPath(iniDirView, nameView), std::wstring(iniDirView) }; } } @@ -197,10 +199,7 @@ namespace desktop_win32 { int officeloader_impl(bool bAllowConsole) { - WCHAR szTargetFileName[MAX_PATH] = {}; - WCHAR szIniDirectory[MAX_PATH]; - - extendLoaderEnvironment(szTargetFileName, szIniDirectory); + const auto& [szTargetFileName, szIniDirectory] = extendLoaderEnvironment(); STARTUPINFOW aStartupInfo; ZeroMemory(&aStartupInfo, sizeof(aStartupInfo)); @@ -221,57 +220,39 @@ int officeloader_impl(bool bAllowConsole) bool fallbackForMaxMemoryInMB = true; bool fallbackForExcludeChildProcesses = true; - const WCHAR* szIniFile = L"\\fundamental.override.ini"; - const size_t nDirLen = wcslen(szIniDirectory); - if (wcslen(szIniFile) + nDirLen < MAX_PATH) + try { - WCHAR szBootstrapIni[MAX_PATH]; - wcscpy(szBootstrapIni, szIniDirectory); - wcscpy(&szBootstrapIni[nDirLen], szIniFile); - - try - { - boost::property_tree::ptree pt; - std::ifstream aFile(szBootstrapIni); - boost::property_tree::ini_parser::read_ini(aFile, pt); - nMaxMemoryInMB = pt.get("Bootstrap.LimitMaximumMemoryInMB", nMaxMemoryInMB); - fallbackForMaxMemoryInMB = !pt.get_child_optional("Bootstrap.LimitMaximumMemoryInMB"); - bExcludeChildProcesses = pt.get("Bootstrap.ExcludeChildProcessesFromLimit", bExcludeChildProcesses); - fallbackForExcludeChildProcesses - = !pt.get_child_optional("Bootstrap.ExcludeChildProcessesFromLimit"); - } - catch (...) - { - nMaxMemoryInMB = 0; - } + boost::property_tree::ptree pt; + std::ifstream aFile(szIniDirectory + L"\\fundamental.override.ini"); + boost::property_tree::ini_parser::read_ini(aFile, pt); + nMaxMemoryInMB = pt.get("Bootstrap.LimitMaximumMemoryInMB", nMaxMemoryInMB); + fallbackForMaxMemoryInMB = !pt.get_child_optional("Bootstrap.LimitMaximumMemoryInMB"); + bExcludeChildProcesses = pt.get("Bootstrap.ExcludeChildProcessesFromLimit", bExcludeChildProcesses); + fallbackForExcludeChildProcesses + = !pt.get_child_optional("Bootstrap.ExcludeChildProcessesFromLimit"); + } + catch (...) + { + nMaxMemoryInMB = 0; } // For backwards compatibility, for now also try to read the values from bootstrap.ini if // fundamental.override.ini does not provide them: if (fallbackForMaxMemoryInMB || fallbackForExcludeChildProcesses) { - const WCHAR* szFallbackIniFile = L"\\bootstrap.ini"; - const size_t nFallbackDirLen = wcslen(szIniDirectory); - if (wcslen(szFallbackIniFile) + nFallbackDirLen < MAX_PATH) + try { - WCHAR szBootstrapIni[MAX_PATH]; - wcscpy(szBootstrapIni, szIniDirectory); - wcscpy(&szBootstrapIni[nFallbackDirLen], szFallbackIniFile); - - try - { - boost::property_tree::ptree pt; - std::ifstream aFile(szBootstrapIni); - boost::property_tree::ini_parser::read_ini(aFile, pt); - if (fallbackForMaxMemoryInMB) { - nMaxMemoryInMB = pt.get("Win32.LimitMaximumMemoryInMB", nMaxMemoryInMB); - } - if (fallbackForExcludeChildProcesses) { - bExcludeChildProcesses = pt.get("Win32.ExcludeChildProcessesFromLimit", bExcludeChildProcesses); - } + boost::property_tree::ptree pt; + std::ifstream aFile(szIniDirectory + L"\\bootstrap.ini"); + boost::property_tree::ini_parser::read_ini(aFile, pt); + if (fallbackForMaxMemoryInMB) { + nMaxMemoryInMB = pt.get("Win32.LimitMaximumMemoryInMB", nMaxMemoryInMB); } - catch (...) - { + if (fallbackForExcludeChildProcesses) { + bExcludeChildProcesses = pt.get("Win32.ExcludeChildProcessesFromLimit", bExcludeChildProcesses); } } + catch (...) + { + } } // create a Windows JobObject with a memory limit @@ -355,9 +336,9 @@ int officeloader_impl(bool bAllowConsole) PROCESS_INFORMATION aProcessInfo; - fSuccess = CreateProcessW(szTargetFileName, lpCommandLine, nullptr, nullptr, TRUE, - bAllowConsole ? 0 : DETACHED_PROCESS, nullptr, szIniDirectory, - &aStartupInfo, &aProcessInfo); + fSuccess = CreateProcessW(szTargetFileName.data(), lpCommandLine, nullptr, nullptr, TRUE, + bAllowConsole ? 0 : DETACHED_PROCESS, nullptr, + szIniDirectory.data(), &aStartupInfo, &aProcessInfo); if (fSuccess) { @@ -402,9 +383,7 @@ int officeloader_impl(bool bAllowConsole) int unopkgloader_impl(bool bAllowConsole) { - WCHAR szTargetFileName[MAX_PATH]; - WCHAR szIniDirectory[MAX_PATH]; - extendLoaderEnvironment(szTargetFileName, szIniDirectory); + const auto& [szTargetFileName, szIniDirectory] = extendLoaderEnvironment(); STARTUPINFOW aStartupInfo{}; aStartupInfo.cb = sizeof(aStartupInfo); @@ -412,50 +391,32 @@ int unopkgloader_impl(bool bAllowConsole) DWORD dwExitCode = DWORD(-1); - size_t iniDirLen = wcslen(szIniDirectory); std::wstring sCWDarg = getCWDarg(); - WCHAR redirect[MAX_PATH]; DWORD dummy; - bool hasRedirect = - tools::buildPath( - redirect, szIniDirectory, szIniDirectory + iniDirLen, - MY_STRING(L"redirect.ini")) != nullptr && - (GetBinaryTypeW(redirect, &dummy) || // cheaper check for file existence? + std::wstring redirect = tools::buildPath(szIniDirectory, L"redirect.ini"); + bool hasRedirect = !redirect.empty() && + (GetBinaryTypeW(redirect.data(), &dummy) || // cheaper check for file existence? GetLastError() != ERROR_FILE_NOT_FOUND); LPWSTR cl1 = GetCommandLineW(); - WCHAR* cl2 = new WCHAR[ - wcslen(cl1) + - (hasRedirect - ? (MY_LENGTH(L" \"-env:INIFILENAME=vnd.sun.star.pathname:") + - iniDirLen + MY_LENGTH(L"redirect.ini\"")) - : 0) + - sCWDarg.size() + 1]; - // 4 * cwdLen: each char preceded by backslash, each trailing backslash - // doubled - WCHAR* p = commandLineAppend(cl2, cl1); - if (hasRedirect) { - p = commandLineAppend(p, L" \"-env:INIFILENAME=vnd.sun.star.pathname:"); - p = commandLineAppend(p, szIniDirectory); - p = commandLineAppend(p, L"redirect.ini\""); - } - commandLineAppend(p, sCWDarg); + std::wstring cl2 = cl1; + if (hasRedirect) + cl2 += L" \"-env:INIFILENAME=vnd.sun.star.pathname:" + redirect + L"\""; + cl2 += sCWDarg; PROCESS_INFORMATION aProcessInfo; bool fSuccess = CreateProcessW( - szTargetFileName, - cl2, + szTargetFileName.data(), + cl2.data(), nullptr, nullptr, TRUE, bAllowConsole ? 0 : DETACHED_PROCESS, nullptr, - szIniDirectory, + szIniDirectory.data(), &aStartupInfo, &aProcessInfo); - delete[] cl2; - if (fSuccess) { DWORD dwWaitResult; diff --git a/desktop/win32/source/unoinfo.cxx b/desktop/win32/source/unoinfo.cxx index 14cee8819dde..28a91b41547d 100644 --- a/desktop/win32/source/unoinfo.cxx +++ b/desktop/win32/source/unoinfo.cxx @@ -50,14 +50,11 @@ void writePath( wchar_t const * frontBegin, wchar_t const * frontEnd, wchar_t const * backBegin, std::size_t backLength) { - wchar_t path[MAX_PATH]; - wchar_t * end = tools::buildPath( - path, frontBegin, frontEnd, backBegin, backLength); - if (end == nullptr) { + std::wstring path = tools::buildPath({ frontBegin, frontEnd }, { backBegin, backLength }); + if (path.empty()) { exit(EXIT_FAILURE); } - std::size_t n = (end - path) * sizeof (wchar_t); - if (fwrite(path, 1, n, stdout) != n) { + if (fwrite(path.data(), sizeof (wchar_t), path.size(), stdout) != path.size()) { exit(EXIT_FAILURE); } } diff --git a/include/tools/pathutils.hxx b/include/tools/pathutils.hxx index 045ec4b96bbe..26696da39260 100644 --- a/include/tools/pathutils.hxx +++ b/include/tools/pathutils.hxx @@ -21,6 +21,9 @@ #include <sal/config.h> +#include <string> +#include <string_view> + #if defined(_WIN32) #include <cstddef> #define WIN32_LEAN_AND_MEAN @@ -49,21 +52,14 @@ WCHAR* filename(WCHAR* path); as there are no symbolic links on Windows (as with symbolic links, x\y\.. and x might denote different directories). - @param path - An output parameter taking the resulting path; must point at a valid - range of memory of size at least MAX_PATH. If NULL is returned, the - content is unspecified. - @param frontBegin, frontEnd - Forms a valid range [frontBegin .. frontEnd) of less than MAX_PATH size. + @param front + First path @param backBegin, backLength - Forms a valid range [backBegin .. backBegin + backLength) of less than - MAX_PATH size. + Second path @return - A pointer to the terminating null character of the concatenation, or NULL - if a failure occurred. + The concatenation, empty if a failure occurred. */ -WCHAR* buildPath(WCHAR* path, WCHAR const* frontBegin, WCHAR const* frontEnd, - WCHAR const* backBegin, std::size_t backLength); +std::wstring buildPath(std::wstring_view front, std::wstring_view back); } #endif diff --git a/pyuno/zipcore/python.cxx b/pyuno/zipcore/python.cxx index 7580e32789e3..b4f3149be128 100644 --- a/pyuno/zipcore/python.cxx +++ b/pyuno/zipcore/python.cxx @@ -79,42 +79,36 @@ int wmain(int argc, wchar_t ** argv, wchar_t **) { exit(EXIT_FAILURE); } } - wchar_t bootstrap[MY_LENGTH(L"vnd.sun.star.pathname:") + MAX_PATH] = - L"vnd.sun.star.pathname:"; //TODO: overflow - wchar_t * bootstrapEnd = tools::buildPath( - bootstrap + MY_LENGTH(L"vnd.sun.star.pathname:"), path, pathEnd, - MY_STRING(L"fundamental.ini")); - if (bootstrapEnd == nullptr) { + std::wstring bootstrap = tools::buildPath({ path, pathEnd }, L"fundamental.ini"); + if (bootstrap.empty()) { exit(EXIT_FAILURE); } - wchar_t pythonpath2[MAX_PATH]; - wchar_t * pythonpath2End = tools::buildPath( - pythonpath2, path, pathEnd, - MY_STRING(L"\\python-core-" PYTHON_VERSION_STRING L"\\lib")); - if (pythonpath2End == nullptr) { + bootstrap = L"vnd.sun.star.pathname:" + bootstrap; + std::wstring pythonpath2 = tools::buildPath( + { path, pathEnd }, + L"\\python-core-" PYTHON_VERSION_STRING L"\\lib"); + if (pythonpath2.empty()) { exit(EXIT_FAILURE); } - wchar_t pythonpath3[MAX_PATH]; - wchar_t * pythonpath3End = tools::buildPath( - pythonpath3, path, pathEnd, - MY_STRING(L"\\python-core-" PYTHON_VERSION_STRING L"\\lib\\site-packages")); - if (pythonpath3End == nullptr) { + std::wstring pythonpath3 = tools::buildPath( + { path, pathEnd }, + L"\\python-core-" PYTHON_VERSION_STRING L"\\lib\\site-packages"); + if (pythonpath3.empty()) { exit(EXIT_FAILURE); } - wchar_t pythonhome[MAX_PATH]; - wchar_t * pythonhomeEnd = tools::buildPath( - pythonhome, path, pathEnd, MY_STRING(L"\\python-core-" PYTHON_VERSION_STRING)); - if (pythonhomeEnd == nullptr) { + std::wstring pythonhome = tools::buildPath( + { path, pathEnd }, + L"\\python-core-" PYTHON_VERSION_STRING); + if (pythonhome.empty()) { exit(EXIT_FAILURE); } - wchar_t pythonexe[MAX_PATH]; - wchar_t * pythonexeEnd = tools::buildPath( - pythonexe, path, pathEnd, - MY_STRING(L"\\python-core-" PYTHON_VERSION_STRING L"\\bin\\python.exe")); - if (pythonexeEnd == nullptr) { + std::wstring pythonexe = tools::buildPath( + { path, pathEnd }, + L"\\python-core-" PYTHON_VERSION_STRING L"\\bin\\python.exe"); + if (pythonexe.empty()) { exit(EXIT_FAILURE); } - std::size_t clSize = MY_LENGTH(L"\"") + 4 * (pythonexeEnd - pythonexe) + + std::size_t clSize = MY_LENGTH(L"\"") + 4 * pythonexe.size() + MY_LENGTH(L"\"\0"); //TODO: overflow // 4 * len: each char preceded by backslash, each trailing backslash // doubled @@ -123,7 +117,7 @@ int wmain(int argc, wchar_t ** argv, wchar_t **) { //TODO: overflow } wchar_t * cl = new wchar_t[clSize]; - wchar_t * cp = encode(cl, pythonhome); + wchar_t * cp = encode(cl, pythonhome.data()); for (int i = 1; i < argc; ++i) { *cp++ = L' '; cp = encode(cp, argv[i]); @@ -169,12 +163,12 @@ int wmain(int argc, wchar_t ** argv, wchar_t **) { exit(EXIT_FAILURE); } } - len = (pathEnd - path) + MY_LENGTH(L";") + (pythonpath2End - pythonpath2) + - MY_LENGTH(L";") + (pythonpath3End - pythonpath3) + + len = (pathEnd - path) + MY_LENGTH(L";") + pythonpath2.size() + + MY_LENGTH(L";") + pythonpath3.size() + (n == 0 ? 0 : MY_LENGTH(L";") + (n - 1)) + 1; //TODO: overflow value = new wchar_t[len]; _snwprintf( - value, len, L"%s;%s;%s%s%s", path, pythonpath2, pythonpath3, + value, len, L"%s;%s;%s%s%s", path, pythonpath2.c_str(), pythonpath3.c_str(), n == 0 ? L"" : L";", orig); if (!SetEnvironmentVariableW(L"PYTHONPATH", value)) { exit(EXIT_FAILURE); @@ -183,13 +177,13 @@ int wmain(int argc, wchar_t ** argv, wchar_t **) { delete [] orig; } delete [] value; - if (!SetEnvironmentVariableW(L"PYTHONHOME", pythonhome)) { + if (!SetEnvironmentVariableW(L"PYTHONHOME", pythonhome.data())) { exit(EXIT_FAILURE); } n = GetEnvironmentVariableW(L"URE_BOOTSTRAP", nullptr, 0); if (n == 0) { if (GetLastError() != ERROR_ENVVAR_NOT_FOUND || - !SetEnvironmentVariableW(L"URE_BOOTSTRAP", bootstrap)) + !SetEnvironmentVariableW(L"URE_BOOTSTRAP", bootstrap.data())) { exit(EXIT_FAILURE); } @@ -199,7 +193,7 @@ int wmain(int argc, wchar_t ** argv, wchar_t **) { startinfo.cb = sizeof (STARTUPINFOW); PROCESS_INFORMATION procinfo; if (!CreateProcessW( - pythonexe, cl, nullptr, nullptr, FALSE, CREATE_UNICODE_ENVIRONMENT, nullptr, + pythonexe.data(), cl, nullptr, nullptr, FALSE, CREATE_UNICODE_ENVIRONMENT, nullptr, nullptr, &startinfo, &procinfo)) { exit(EXIT_FAILURE); } diff --git a/tools/qa/cppunit/test_pathutils.cxx b/tools/qa/cppunit/test_pathutils.cxx index 7ad75f1e8db2..a7a065c34761 100644 --- a/tools/qa/cppunit/test_pathutils.cxx +++ b/tools/qa/cppunit/test_pathutils.cxx @@ -26,13 +26,11 @@ namespace { -void buildPath(wchar_t const* front, wchar_t const* back, wchar_t const* path) +void buildPath(std::wstring_view front, std::wstring_view back, wchar_t const* path) { #if defined(_WIN32) - wchar_t p[MAX_PATH]; - wchar_t* e = tools::buildPath(p, front, front + std::wcslen(front), back, std::wcslen(back)); - CPPUNIT_ASSERT_EQUAL(static_cast<void*>(p + std::wcslen(path)), static_cast<void*>(e)); - CPPUNIT_ASSERT_EQUAL(0, std::wcscmp(path, p)); + std::wstring s = tools::buildPath(front, back); + CPPUNIT_ASSERT_EQUAL(0, std::wcscmp(path, s.c_str())); #else (void)front; (void)back; diff --git a/tools/source/misc/pathutils.cxx b/tools/source/misc/pathutils.cxx index 706740a320f9..30bdbde8f013 100644 --- a/tools/source/misc/pathutils.cxx +++ b/tools/source/misc/pathutils.cxx @@ -43,63 +43,40 @@ WCHAR * filename(WCHAR * path) { } } -WCHAR * buildPath( - WCHAR * path, WCHAR const * frontBegin, WCHAR const * frontEnd, - WCHAR const * backBegin, std::size_t backLength) +std::wstring buildPath(std::wstring_view front, std::wstring_view back) { // Remove leading ".." segments in the second path together with matching // segments in the first path that are neither empty nor "." nor ".." nor // end in ":" (which is not foolproof, as it can erroneously erase the start // of a UNC path, but only if the input is bad data): - while (backLength >= 2 && backBegin[0] == L'.' && backBegin[1] == L'.' && - (backLength == 2 || backBegin[2] == L'\\')) + while (back.starts_with(L"..") && + (back.size() == 2 || back[2] == L'\\')) { - if (frontEnd - frontBegin < 2 || frontEnd[-1] != L'\\' || - frontEnd[-2] == L'\\' || frontEnd[-2] == L':' || - (frontEnd[-2] == L'.' && - (frontEnd - frontBegin < 3 || frontEnd[-3] == L'\\' || - (frontEnd[-3] == L'.' && - (frontEnd - frontBegin < 4 || frontEnd[-4] == L'\\'))))) + if (front.size() < 2 || front.back() != L'\\' || + front[front.size() - 2] == L'\\' || front[front.size() - 2] == L':' || + (front[front.size() - 2] == L'.' && + (front.size() < 3 || front[front.size() - 3] == L'\\' || + (front[front.size() - 3] == L'.' && + (front.size() < 4 || front[front.size() - 4] == L'\\'))))) { break; } - WCHAR const * p = frontEnd - 1; - while (p != frontBegin && p[-1] != L'\\') { + auto p = front.end() - 1; + while (p != front.begin() && p[-1] != L'\\') { --p; } - if (p == frontBegin) { + if (p == front.begin()) { break; } - frontEnd = p; - if (backLength == 2) { - backBegin += 2; - backLength -= 2; + front.remove_suffix(front.end() - p); + if (back.size() == 2) { + back = {}; } else { - backBegin += 3; - backLength -= 3; + back.remove_prefix(3); } } - if (backLength < - o3tl::make_unsigned(MAX_PATH - (frontEnd - frontBegin))) - { - WCHAR * p; - if (frontBegin == path) { - p = const_cast< WCHAR * >(frontEnd); - } else { - p = path; - while (frontBegin != frontEnd) { - *p++ = *frontBegin++; - } - } - for (; backLength > 0; --backLength) { - *p++ = *backBegin++; - } - *p = L'\0'; - return p; - } else { - SetLastError(ERROR_FILENAME_EXCED_RANGE); - return nullptr; - } + + return std::wstring(front) + std::wstring(back); } } |