diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2018-10-02 15:55:05 +0300 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2018-10-22 10:22:46 +0200 |
commit | 0b92d04ab61b4d39d714df6210d6f6bf8fdec5bf (patch) | |
tree | 7c81b2944c90419ccbb37b661bb052ba570a9e5e /desktop/win32 | |
parent | 0f262a4c8b2f72e35881bddc31a8899e2506eca7 (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.cxx | 78 |
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; } |