mirror of
https://github.com/Xevion/easy7zip.git
synced 2026-01-31 06:24:13 -06:00
fixes vulnerable command line parsing
- considers valid windows escape sequences, like backslashes followed by quote-char as well as quote triples) - SplitCommandLine works now very similar to CommandLineToArgvW (but doesn't require dependency to shell32) Signed-off-by: Sergey G. Brester <serg.brester@sebres.de> Reviewed-by: Tino Reichardt <milky-zfs@mcmilk.de>
This commit is contained in:
@@ -8,24 +8,75 @@ namespace NCommandLineParser {
|
|||||||
|
|
||||||
bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2)
|
bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2)
|
||||||
{
|
{
|
||||||
|
unsigned qcount = 0, bcount = 0;
|
||||||
|
wchar_t c; const wchar_t *s = src.Ptr();
|
||||||
|
|
||||||
dest1.Empty();
|
dest1.Empty();
|
||||||
dest2.Empty();
|
|
||||||
bool quoteMode = false;
|
while ((c = *s++) != 0)
|
||||||
unsigned i;
|
|
||||||
for (i = 0; i < src.Len(); i++)
|
|
||||||
{
|
{
|
||||||
wchar_t c = src[i];
|
switch (c)
|
||||||
if ((c == L' ' || c == L'\t') && !quoteMode)
|
|
||||||
{
|
{
|
||||||
dest2 = src.Ptr(i + 1);
|
case L'\\':
|
||||||
return i != 0;
|
// a backslash - firstly add it as a regular char,
|
||||||
|
// we'll delete escaped later (if followed by quote):
|
||||||
|
dest1 += c;
|
||||||
|
bcount++;
|
||||||
|
break;
|
||||||
|
case L'"':
|
||||||
|
// check quote char is escaped:
|
||||||
|
if (!(bcount & 1))
|
||||||
|
{
|
||||||
|
// preceded by an even number of '\', this is half that
|
||||||
|
// number of '\' (delete bcount/2 chars):
|
||||||
|
dest1.DeleteFrom(dest1.Len() - bcount/2);
|
||||||
|
// count quote chars:
|
||||||
|
qcount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// preceded by an odd number of '\', this is half that
|
||||||
|
// number of '\' followed by an escaped '"':
|
||||||
|
dest1.DeleteFrom(dest1.Len() - bcount/2 - 1);
|
||||||
|
dest1 += L'"';
|
||||||
|
}
|
||||||
|
bcount = 0;
|
||||||
|
// now count the number of consecutive quotes (inclusive
|
||||||
|
// the quote that lead us here):
|
||||||
|
while (*s == L'"')
|
||||||
|
{
|
||||||
|
s++;
|
||||||
|
if (++qcount == 3)
|
||||||
|
{
|
||||||
|
dest1 += L'"';
|
||||||
|
qcount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (qcount == 2)
|
||||||
|
qcount = 0;
|
||||||
|
break;
|
||||||
|
case L' ':
|
||||||
|
case L'\t':
|
||||||
|
// a space (end of arg or regular char):
|
||||||
|
if (!qcount)
|
||||||
|
{
|
||||||
|
// end of argument:
|
||||||
|
bcount = 0;
|
||||||
|
// skip to the next one:
|
||||||
|
while (isblank(*s)) { s++; };
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
// no break - a space as regular char:
|
||||||
|
default:
|
||||||
|
// a regular character
|
||||||
|
dest1 += c;
|
||||||
|
bcount = 0;
|
||||||
}
|
}
|
||||||
if (c == L'\"')
|
|
||||||
quoteMode = !quoteMode;
|
|
||||||
else
|
|
||||||
dest1 += c;
|
|
||||||
}
|
}
|
||||||
return i != 0;
|
s--; // back to NTS-zero char
|
||||||
|
done:
|
||||||
|
dest2 = s;
|
||||||
|
return (dest1.Len() || src[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplitCommandLine(const UString &s, UStringVector &parts)
|
void SplitCommandLine(const UString &s, UStringVector &parts)
|
||||||
|
|||||||
Reference in New Issue
Block a user