desktop/win32/source/loader.cxx     |  203 ++++++++++++++----------------------
 desktop/win32/source/unoinfo.cxx    |    9 -
 include/tools/pathutils.hxx         |   20 +--
 pyuno/zipcore/python.cxx            |   60 ++++------
 tools/qa/cppunit/test_pathutils.cxx |    8 -
 tools/source/misc/pathutils.cxx     |   59 +++-------
 6 files changed, 141 insertions(+), 218 deletions(-)

New commits:
commit 3234c4e35fe97cffb87f785614b3b593e2237310
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Wed Jan 24 16:52:21 2024 +0600
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Sun Feb 25 07:29:40 2024 +0100

    Avoid MAX_PATH limitation in launcher
    
    ... and drop some manual memory management.
    
    Change-Id: I4c60ce559ff185d4685a6b9799a97651438115b1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162502
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

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'
-        *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'
-    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"\"
         // 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'
-        return p;
-    } else {
-        SetLastError(ERROR_FILENAME_EXCED_RANGE);
-        return nullptr;
-    }
+
+    return std::wstring(front) + std::wstring(back);
 }
 
 }

Reply via email to