From 28c9b674149bd8f0d5106a73fdbce57a6b1f2558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 26 Sep 2024 14:41:06 +0800 Subject: [PATCH] Processing (Windows): correctly escaping arguments --- src/common/processing_windows.c | 45 ++++++++++++++++++++++++++++----- src/data/help.json | 2 +- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/common/processing_windows.c b/src/common/processing_windows.c index 03fb7cbfd..c2d2b10fa 100644 --- a/src/common/processing_windows.c +++ b/src/common/processing_windows.c @@ -8,6 +8,43 @@ enum { FF_PIPE_BUFSIZ = 8192 }; +static void argvToCmdline(char* const argv[], FFstrbuf* result) +{ + // From https://gist.github.com/jin-x/cdd641d98887524b091fb1f82a68717d + + FF_STRBUF_AUTO_DESTROY temp = ffStrbufCreate(); + for (int i = 0; argv[i] != NULL; i++) + { + ffStrbufSetS(&temp, argv[i]); + // Add slash (\) before double quotes (") and duplicate slashes before it + for ( + uint32_t pos = ffStrbufFirstIndexC(&temp, '"'), cnt; + pos != temp.length; + pos = ffStrbufNextIndexC(&temp, pos + cnt * 2, '"') + ) { + cnt = 1; + while (pos > 0 && temp.chars[pos - 1] == '\\') { ++cnt, --pos; } + ffStrbufInsertNC(&temp, pos, cnt, '\\'); + } + + // Add quotes around string if whitespace chars are present (with slash duplicating at the end of string) + if (ffStrbufFirstIndexS(&temp, " \t") != temp.length) + { + uint32_t pos = temp.length; + uint32_t cnt = 0; + while (pos > 0 && temp.chars[pos - 1] == '\\') { ++cnt, --pos; } + if (cnt > 0) ffStrbufAppendNC(&temp, cnt, '\\'); + ffStrbufPrependC(&temp, '"'); + ffStrbufAppendC(&temp, '"'); + } + + // Add space delimiter + if (i > 0) ffStrbufAppendC(result, ' '); + ffStrbufAppend(result, &temp); + ffStrbufClear(&temp); + } +} + const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr) { int timeout = instance.config.general.processingTimeout; @@ -55,12 +92,8 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use else siStartInfo.hStdOutput = hChildPipeWrite; - FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreateF("\"%s\"", argv[0]); - for(char* const* parg = &argv[1]; *parg; ++parg) - { - ffStrbufAppendC(&cmdline, ' '); - ffStrbufAppendS(&cmdline, *parg); - } + FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreate(); + argvToCmdline(argv, &cmdline); success = CreateProcessA( NULL, // application name diff --git a/src/data/help.json b/src/data/help.json index 486c6c61f..0d3424adb 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -1379,7 +1379,7 @@ { "long": "command-param", "desc": "Set the parameter used when starting the shell", - "remark": "Due to the difference of how OSes handle command line parameters, Windows will parse whitespaces as param separators, while *nix will not", + "remark": "If set to empty string, it will be ignored", "arg": { "type": "str", "default": "\"/c\" for Windows; \"-c\" for *nix"