Skip to content

Commit 61870d0

Browse files
committed
Implement raw command-line parsing for -- delimiter
Parse the raw command line string to properly detect the `--` separator before argument splitting. This ensures that quoted arguments containing the `--` delimiter are handled correctly and not mistakenly treated as separators. The previous approach used `CommandLineToArgvW` which splits arguments before parsing, making it impossible to distinguish between a quoted `--` in an argument and the actual separator. Changes: - Add `FindSeparator()` to locate `--` in raw command line with proper quote and escape handling - Modify `GetArguments()` to split raw command line at separator - Remove `--` handling from `parse_command_line()` since it's now done earlier - Return separate `syringe_args` and `game_args` from `GetArguments()` Signed-off-by: 舰队的偶像-岛风酱 <frg2089@outlook.com>
1 parent 075782d commit 61870d0

2 files changed

Lines changed: 70 additions & 32 deletions

File tree

Main.cpp

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,61 @@
88
#include <commctrl.h>
99
#include <shellapi.h>
1010

11-
std::vector<std::string> GetArguments()
11+
struct Arguments
1212
{
13+
std::vector<std::string> syringe_args;
14+
std::string game_args;
15+
};
16+
17+
size_t FindSeparator(const std::wstring& cmdLine)
18+
{
19+
bool inQuotes = false;
20+
size_t len = cmdLine.length();
21+
for (size_t i = 0; i < len; ++i)
22+
{
23+
if (cmdLine[i] == L'\\' && i + 1 < len && cmdLine[i + 1] == L'"')
24+
{
25+
i += 1;
26+
continue;
27+
}
28+
29+
if (cmdLine[i] == L'"')
30+
{
31+
inQuotes = !inQuotes;
32+
continue;
33+
}
34+
35+
if (!inQuotes && cmdLine[i] == L' ')
36+
{
37+
if (i + 3 < len && cmdLine[i + 1] == L'-' && cmdLine[i + 2] == L'-' && cmdLine[i + 3] == L' ')
38+
{
39+
return i;
40+
}
41+
}
42+
}
43+
return std::wstring::npos;
44+
}
45+
46+
Arguments GetArguments()
47+
{
48+
std::wstring wszSyringeArgs;
49+
std::wstring wszGameArgs;
50+
std::wstring lpCmdLine = GetCommandLineW();
51+
auto separator = FindSeparator(lpCmdLine);
52+
if (separator != std::wstring::npos)
53+
{
54+
wszSyringeArgs = lpCmdLine.substr(0, separator);
55+
wszGameArgs = lpCmdLine.substr(separator + 4);
56+
}
57+
else
58+
{
59+
wszSyringeArgs = lpCmdLine;
60+
wszGameArgs = L"";
61+
}
62+
1363
// Get argc, argv in wide chars
1464
int argc = 0;
15-
LPWSTR* argvW = CommandLineToArgvW(GetCommandLineW(), &argc);
65+
LPWSTR* argvW = CommandLineToArgvW(wszSyringeArgs.c_str(), &argc);
1666

1767
// Convert to UTF-8. Skip the first argument as it contains the path to Syringe itself
1868
std::vector<std::string> argv(argc - 1);
@@ -25,10 +75,17 @@ std::vector<std::string> GetArguments()
2575

2676
LocalFree(argvW);
2777

28-
return argv;
78+
int len = WideCharToMultiByte(CP_UTF8, 0, wszGameArgs.c_str(), -1, nullptr, 0, nullptr, nullptr);
79+
std::string gameArgs = std::string(len - 1, '\0');
80+
WideCharToMultiByte(CP_UTF8, 0, wszGameArgs.c_str(), -1, gameArgs.data(), len, nullptr, nullptr);
81+
82+
return {
83+
argv,
84+
gameArgs,
85+
};
2986
}
3087

31-
int Run(const std::vector<std::string>& arguments)
88+
int Run(const Arguments& arguments)
3289
{
3390
constexpr auto const VersionString = "SyringeEx " SYRINGEEX_VER_TEXT ", based on Syringe 0.7.2.0";
3491

@@ -39,14 +96,14 @@ int Run(const std::vector<std::string>& arguments)
3996
Log::WriteLine(VersionString);
4097
Log::WriteLine("===============");
4198
Log::WriteLine();
42-
Log::WriteLine("WinMain: arguments = \"%.*s\"", printable(arguments));
99+
Log::WriteLine("WinMain: arguments = \"%.*s\"", printable(arguments.syringe_args));
43100

44101
auto failure = "Could not load executable.";
45102
auto exit_code = ERROR_ERRORS_ENCOUNTERED;
46103

47104
try
48105
{
49-
auto const command = parse_command_line(arguments);
106+
auto const command = parse_command_line(arguments.syringe_args);
50107

51108
Log::WriteLine(
52109
"WinMain: Trying to load executable file \"%.*s\"...",
@@ -62,10 +119,10 @@ int Run(const std::vector<std::string>& arguments)
62119

63120
Log::WriteLine(
64121
"WinMain: SyringeDebugger::Run(\"%.*s\");",
65-
printable(command.game_arguments));
122+
printable(arguments.game_args));
66123
Log::WriteLine();
67124

68-
Debugger.Run(command.game_arguments);
125+
Debugger.Run(arguments.game_args);
69126
Log::WriteLine("WinMain: SyringeDebugger::Run finished.");
70127
Log::WriteLine("WinMain: Exiting on success.");
71128
return ERROR_SUCCESS;
@@ -84,7 +141,7 @@ int Run(const std::vector<std::string>& arguments)
84141
{
85142
MessageBoxA(
86143
nullptr, "Syringe cannot be run like that.\n\n"
87-
"Usage:\nSyringe.exe <exe name> [-i=<injectedfile.dll> ...] [-- <arguments>]",
144+
"Usage:\nSyringe.exe <exe name> [-i=<injectedfile.dll> ...] [-- <arguments>]",
88145
VersionString, MB_OK | MB_ICONINFORMATION);
89146

90147
Log::WriteLine(

Support.h

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ inline auto parse_command_line(const std::vector<std::string>& arguments)
3232
{
3333
std::vector<std::string> syringe_arguments;
3434
std::string executable_name;
35-
std::string game_arguments;
3635
};
3736

3837
if (arguments.empty())
@@ -43,8 +42,6 @@ inline auto parse_command_line(const std::vector<std::string>& arguments)
4342
// First non-flag argument becomes executable name
4443
bool exe_found = false;
4544

46-
bool exe_arguments = false;
47-
4845
for (const auto& arg : arguments)
4946
{
5047
// executable name: first argument not starting with '-'
@@ -59,32 +56,16 @@ inline auto parse_command_line(const std::vector<std::string>& arguments)
5956
continue;
6057
}
6158

62-
if (arg == "--")
63-
{
64-
exe_arguments = true;
65-
continue;
66-
}
67-
68-
if (exe_arguments)
69-
{
70-
// game arguments
71-
ret.game_arguments += " ";
72-
ret.game_arguments += arg;
73-
}
59+
// Syringe arguments
60+
if (arg.starts_with("-i=\"") && arg.ends_with('"'))
61+
ret.syringe_arguments.push_back("-i=" + arg.substr(4, arg.length() - 5));
7462
else
75-
{
76-
// Syringe arguments
77-
if (arg.starts_with("-i=\"") && arg.ends_with('"'))
78-
ret.syringe_arguments.push_back("-i=" + arg.substr(4, arg.length() - 5));
79-
else
80-
ret.syringe_arguments.push_back(arg);
81-
}
63+
ret.syringe_arguments.push_back(arg);
8264
}
8365

8466
if (!exe_found || ret.executable_name.empty())
8567
throw invalid_command_arguments{};
8668

87-
ret.game_arguments = ret.game_arguments.substr(1);
8869

8970
return ret;
9071
}

0 commit comments

Comments
 (0)