summaryrefslogtreecommitdiff
path: root/desktop/win32
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2018-10-02 15:55:05 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2018-10-22 10:22:46 +0200
commit0b92d04ab61b4d39d714df6210d6f6bf8fdec5bf (patch)
tree7c81b2944c90419ccbb37b661bb052ba570a9e5e /desktop/win32
parent0f262a4c8b2f72e35881bddc31a8899e2506eca7 (diff)
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@collabora.com>
Diffstat (limited to 'desktop/win32')
-rw-r--r--desktop/win32/source/officeloader/officeloader.cxx78
1 files changed, 55 insertions, 23 deletions
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;
}