[Libreoffice-commits] core.git: desktop/win32

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Mon Oct 22 08:23:08 UTC 2018


 desktop/win32/source/officeloader/officeloader.cxx |   78 ++++++++++++++-------
 1 file changed, 55 insertions(+), 23 deletions(-)

New commits:
commit 0b92d04ab61b4d39d714df6210d6f6bf8fdec5bf
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Tue Oct 2 15:55:05 2018 +0300
Commit:     Mike Kaganski <mike.kaganski at collabora.com>
CommitDate: Mon Oct 22 10:22:46 2018 +0200

    tdf#120249: fix escaping to handle quotes and multiple trailing backslshes
    
    Follow-up of commit f4103a42d58535e21c48ff94ab000ab0305c62e3
    
    Change-Id: I4562386d3151875dff8e9eddf31c4af3333cefb7
    Reviewed-on: https://gerrit.libreoffice.org/61245
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>

diff --git a/desktop/win32/source/officeloader/officeloader.cxx b/desktop/win32/source/officeloader/officeloader.cxx
index cd471ca2a5f9..e1b3323fbe9e 100644
--- a/desktop/win32/source/officeloader/officeloader.cxx
+++ b/desktop/win32/source/officeloader/officeloader.cxx
@@ -21,6 +21,9 @@
 
 #include <systools/win32/uwinapi.h>
 #include <stdlib.h>
+#include <algorithm>
+#include <string>
+#include <vector>
 #include <desktop/exithelper.h>
 
 #include "../loader.hxx"
@@ -30,6 +33,38 @@ static LPWSTR *GetCommandArgs( int *pArgc )
     return CommandLineToArgvW( GetCommandLineW(), pArgc );
 }
 
+// tdf#120249: quotes in arguments need to be escaped; backslashes before quotes need doubling. See
+// https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/nf-shellapi-commandlinetoargvw
+static std::wstring EscapeArg(LPCWSTR sArg)
+{
+    const size_t nOrigSize = wcslen(sArg);
+    LPCWSTR const end = sArg + nOrigSize;
+    std::wstring sResult(L"\"");
+
+    LPCWSTR lastPosQuote = sArg;
+    LPCWSTR posQuote;
+    while ((posQuote = std::find(lastPosQuote, end, L'"')) != end)
+    {
+        LPCWSTR posBackslash = posQuote;
+        while (posBackslash != lastPosQuote && *(posBackslash - 1) == L'\\')
+            --posBackslash;
+
+        sResult.append(lastPosQuote, posBackslash);
+        sResult.append((posQuote - posBackslash) * 2 + 1, L'\\'); // 2n+1 '\' to escape the '"'
+        sResult.append(1, L'"');
+        lastPosQuote = posQuote + 1;
+    }
+
+    LPCWSTR posTrailingBackslashSeq = end;
+    while (posTrailingBackslashSeq != lastPosQuote && *(posTrailingBackslashSeq - 1) == L'\\')
+        --posTrailingBackslashSeq;
+    sResult.append(lastPosQuote, posTrailingBackslashSeq);
+    sResult.append((end - posTrailingBackslashSeq) * 2, L'\\'); // 2n '\' before closing '"'
+    sResult.append(1, L'"');
+
+    return sResult;
+}
+
 int WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )
 {
     WCHAR        szTargetFileName[MAX_PATH] = {};
@@ -56,48 +91,46 @@ int WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )
 
     BOOL    fSuccess = FALSE;
     LPWSTR  lpCommandLine = nullptr;
-    int argc = 0;
-    LPWSTR * argv = nullptr;
     bool bFirst = true;
     WCHAR cwd[MAX_PATH];
     DWORD cwdLen = GetCurrentDirectoryW(MAX_PATH, cwd);
     if (cwdLen >= MAX_PATH) {
         cwdLen = 0;
     }
+    std::vector<std::wstring> aEscapedArgs;
 
     do
     {
         if ( bFirst ) {
-            argv = GetCommandArgs(&argc);
-            std::size_t n = wcslen(argv[0]) + 2;
-            for (int i = 1; i < argc; ++i) {
-                n += wcslen(argv[i]) + 4; // 2 doublequotes + a space + optional trailing backslash
+            int argc = 0;
+            LPWSTR* argv = GetCommandArgs(&argc);
+            std::size_t n = 0;
+            for (int i = 0; i < argc; ++i) {
+                std::wstring sEscapedArg = EscapeArg(argv[i]);
+                aEscapedArgs.push_back(sEscapedArg);
+                n += sEscapedArg.length() + 1; // a space between args
             }
+            LocalFree(argv);
             n += MY_LENGTH(L" \"-env:OOO_CWD=2") + 4 * cwdLen +
                 MY_LENGTH(L"\"") + 1;
                 // 4 * cwdLen: each char preceded by backslash, each trailing
                 // backslash doubled
             lpCommandLine = new WCHAR[n];
         }
-        WCHAR * p = desktop_win32::commandLineAppend(
-            lpCommandLine, MY_STRING(L"\""));
-        p = desktop_win32::commandLineAppend(p, argv[0]);
-        for (int i = 1; i < argc; ++i) {
-            if (bFirst || EXITHELPER_NORMAL_RESTART == dwExitCode || wcsncmp(argv[i], MY_STRING(L"-env:")) == 0) {
-                p = desktop_win32::commandLineAppend(p, MY_STRING(L"\" \""));
-                p = desktop_win32::commandLineAppend(p, argv[i]);
-                const size_t arglen = wcslen(argv[i]);
-                // tdf#120249: if an argument ends with backslash, we should escape it with another
-                // backslash; otherwise, the trailing backslash will be treated as an escapement
-                // character for the following doublequote by CommandLineToArgvW in soffice.bin. See
-                // https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/nf-shellapi-commandlinetoargvw
-                if (arglen && argv[i][arglen-1] == '\\')
-                    p = desktop_win32::commandLineAppend(p, MY_STRING(L"\\"));
+        WCHAR* p = desktop_win32::commandLineAppend(lpCommandLine, aEscapedArgs[0].c_str(),
+                                                    aEscapedArgs[0].length());
+        for (size_t i = 1; i < aEscapedArgs.size(); ++i)
+        {
+            const std::wstring& rArg = aEscapedArgs[i];
+            if (bFirst || EXITHELPER_NORMAL_RESTART == dwExitCode
+                || wcsncmp(rArg.c_str(), MY_STRING(L"\"-env:")) == 0)
+            {
+                p = desktop_win32::commandLineAppend(p, MY_STRING(L" "));
+                p = desktop_win32::commandLineAppend(p, rArg.c_str(), rArg.length());
             }
         }
 
-        p = desktop_win32::commandLineAppend(
-            p, MY_STRING(L"\" \"-env:OOO_CWD="));
+        p = desktop_win32::commandLineAppend(p, MY_STRING(L" \"-env:OOO_CWD="));
         if (cwdLen == 0) {
             p = desktop_win32::commandLineAppend(p, MY_STRING(L"0"));
         } else {
@@ -181,7 +214,6 @@ int WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )
     } while ( fSuccess
               && ( EXITHELPER_CRASH_WITH_RESTART == dwExitCode || EXITHELPER_NORMAL_RESTART == dwExitCode ));
     delete[] lpCommandLine;
-    LocalFree(argv);
 
     return fSuccess ? dwExitCode : -1;
 }


More information about the Libreoffice-commits mailing list