Implemented encoding the Unicode command-line.

This commit is contained in:
LoRd_MuldeR 2020-10-01 15:45:56 +02:00
parent b263aba3c0
commit 73af54ae58
2 changed files with 203 additions and 16 deletions

View File

@ -49,8 +49,8 @@ END
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,3,0,0 FILEVERSION 0,4,0,0
PRODUCTVERSION 0,3,0,0 PRODUCTVERSION 0,4,0,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x3L FILEFLAGS 0x3L
@ -67,8 +67,8 @@ BEGIN
BEGIN BEGIN
VALUE "ProductName", "Launch5j" VALUE "ProductName", "Launch5j"
VALUE "FileDescription", "Launch5j" VALUE "FileDescription", "Launch5j"
VALUE "ProductVersion", "0.3.0" VALUE "ProductVersion", "0.4.0"
VALUE "FileVersion", "0.3.0" VALUE "FileVersion", "0.4.0"
VALUE "InternalName", "Launch5j" VALUE "InternalName", "Launch5j"
VALUE "OriginalFilename", "launch5j.exe" VALUE "OriginalFilename", "launch5j.exe"
VALUE "LegalCopyright", "Created by LoRd_MuldeR <MuldeR2@GMX.de>" VALUE "LegalCopyright", "Created by LoRd_MuldeR <MuldeR2@GMX.de>"

View File

@ -83,7 +83,7 @@ static wchar_t *vawprintf(const wchar_t *const fmt, va_list ap)
return NULL; return NULL;
} }
const int result = vswprintf(buffer, ((size_t)str_len) + 1U, fmt, ap); const int result = _vsnwprintf(buffer, ((size_t)str_len) + 1U, fmt, ap);
if (result < 1) if (result < 1)
{ {
free(buffer); free(buffer);
@ -152,6 +152,115 @@ static wchar_t *wcstrim(wchar_t *const str)
return str; return str;
} }
/* ======================================================================== */
/* Character encoding */
/* ======================================================================== */
static const char *const HEX_CHARS = "0123456789ABCDEF";
static CHAR *utf16_to_bytes(const wchar_t *const input, const UINT code_page)
{
CHAR *buffer;
DWORD buffer_size = 0U, result = 0U;
buffer_size = WideCharToMultiByte(code_page, 0, input, -1, NULL, 0, NULL, NULL);
if(buffer_size < 1U)
{
return NULL;
}
buffer = (CHAR*) malloc(sizeof(CHAR) * buffer_size);
if(!buffer)
{
return NULL;
}
result = WideCharToMultiByte(code_page, 0, input, -1, (LPSTR)buffer, buffer_size, NULL, NULL);
if((result > 0U) && (result <= buffer_size))
{
return buffer;
}
free(buffer);
return NULL;
}
static BOOL char_needs_encoding(const CHAR c)
{
if (((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')))
{
return FALSE;
}
if ((c == '-') || (c == '_') || (c == '.') || (c == '*') || (c == ' '))
{
return FALSE;
}
return TRUE;
}
static size_t url_encoded_length(const CHAR *const input)
{
if ((input) && input[0U])
{
size_t length = strlen(input);
for (size_t i = 0U; input[i]; ++i)
{
if (char_needs_encoding(input[i]))
{
length += 2U;
}
}
return length + 1U;
}
return 0U;
}
static const wchar_t *url_encode_str(const CHAR *const input)
{
const size_t buffer_size = url_encoded_length(input);
if(buffer_size < 1U)
{
return NULL;
}
wchar_t *buffer = (wchar_t*) malloc(sizeof(wchar_t) * buffer_size);
if (!buffer)
{
return NULL;
}
size_t j = 0U;
for (size_t i = 0U; input[i]; ++i)
{
if (char_needs_encoding(input[i]))
{
buffer[j++] = L'%';
buffer[j++] = (wchar_t) HEX_CHARS[(((BYTE)input[i]) >> 4) & 0xF];
buffer[j++] = (wchar_t) HEX_CHARS[ ((BYTE)input[i]) & 0xF];
}
else
{
buffer[j++] = (wchar_t) ((input[i] != ' ') ? input[i] : '+');
}
}
buffer[j] = '\0';
return buffer;
}
static const wchar_t *url_encode_wcs(const wchar_t *const input, const UINT code_page)
{
const CHAR *byte_string = utf16_to_bytes(input, code_page);
if (!byte_string)
{
return NULL;
}
const wchar_t *encoded = url_encode_str(byte_string);
free((void*)byte_string);
return encoded;
}
/* ======================================================================== */ /* ======================================================================== */
/* System information */ /* System information */
/* ======================================================================== */ /* ======================================================================== */
@ -818,6 +927,69 @@ static DWORD load_java_bitness(const HINSTANCE hinstance, const UINT id)
return ((value == 32U) || (value == 64U)) ? value : 0U; return ((value == 32U) || (value == 64U)) ? value : 0U;
} }
/* ======================================================================== */
/* Command-line */
/* ======================================================================== */
static wchar_t *encode_commandline_args(const int argc, const LPWSTR *const argv)
{
wchar_t *result_buffer = NULL;
if (argv && (argc > 0))
{
const wchar_t **encoded_argv = (const wchar_t**) malloc(sizeof(wchar_t*) * argc);
if (encoded_argv)
{
size_t total_len = 0U;
for (int i = 0; i < argc; ++i)
{
if (NOT_EMPTY(encoded_argv[i] = url_encode_wcs(argv[i], CP_UTF8)))
{
total_len += (wcslen(encoded_argv[i]) + 1U);
}
}
if (total_len > 0U)
{
if ((result_buffer = (wchar_t*) calloc( total_len, sizeof(wchar_t))))
{
for(int i = 0; i < argc; ++i)
{
if (NOT_EMPTY(encoded_argv[i]))
{
if(result_buffer[0U])
{
wcscat(result_buffer, L" ");
}
wcscat(result_buffer, encoded_argv[i]);
}
}
}
}
for (int i = 0; i < argc; ++i)
{
free((void*)encoded_argv[i]);
}
free(encoded_argv);
}
}
return result_buffer;
}
static const wchar_t *encode_commandline(const wchar_t *const command_line)
{
const wchar_t * encoded = NULL;
if (NOT_EMPTY(command_line))
{
int argc = 0;
const LPWSTR *const argv = CommandLineToArgvW(command_line, &argc);
if (argv)
{
encoded = encode_commandline_args(argc, argv);
LocalFree((HLOCAL)argv);
}
}
return encoded;
}
/* ======================================================================== */ /* ======================================================================== */
/* Splash screen */ /* Splash screen */
/* ======================================================================== */ /* ======================================================================== */
@ -1087,11 +1259,11 @@ static void destroy_window(HWND *const hwnd)
static wchar_t *const DEFAULT_HEADING = L"Launch5j"; static wchar_t *const DEFAULT_HEADING = L"Launch5j";
#define APP_HEADING (AVAILABLE(app_heading) ? app_heading : DEFAULT_HEADING) #define APP_HEADING (AVAILABLE(app_heading) ? app_heading : DEFAULT_HEADING)
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE _hPrevInstance, PWSTR pCmdLine, int _nCmdShow)
{ {
int result = -1; int result = -1;
const wchar_t *app_heading = NULL, *mutex_name = NULL, *executable_path = NULL, *executable_directory = NULL, *jarfile_path = NULL, const wchar_t *app_heading = NULL, *mutex_name = NULL, *executable_path = NULL, *executable_directory = NULL, *jarfile_path = NULL, *java_runtime_path = NULL,
*java_runtime_path = NULL, *jre_relative_path = NULL, *jvm_extra_args = NULL, *cmd_extra_args = NULL, *command_line = NULL; *jre_relative_path = NULL, *jvm_extra_args = NULL, *cmd_extra_args = NULL, *cmd_args_encoded = NULL, *ext_args_encoded = NULL, *command_line = NULL;
HANDLE mutex_handle = NULL; HANDLE mutex_handle = NULL;
DWORD java_required_bitness = 0U; DWORD java_required_bitness = 0U;
ULONGLONG java_required_ver_min = 0ULL, java_required_ver_max = 0ULL; ULONGLONG java_required_ver_min = 0ULL, java_required_ver_max = 0ULL;
@ -1107,6 +1279,9 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
SecureZeroMemory(&startup_info, sizeof(STARTUPINFOW)); SecureZeroMemory(&startup_info, sizeof(STARTUPINFOW));
SecureZeroMemory(&process_info, sizeof(PROCESS_INFORMATION)); SecureZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));
// Get current process ID
const DWORD pid = GetCurrentProcessId();
// Load title // Load title
app_heading = load_string(hInstance, ID_STR_HEADING); app_heading = load_string(hInstance, ID_STR_HEADING);
@ -1210,14 +1385,24 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
jvm_extra_args = load_string(hInstance, ID_STR_JVMARGS); jvm_extra_args = load_string(hInstance, ID_STR_JVMARGS);
cmd_extra_args = load_string(hInstance, ID_STR_CMDARGS); cmd_extra_args = load_string(hInstance, ID_STR_CMDARGS);
// Build the command-line // Get user-provided command-line args
command_line = AVAILABLE(cmd_extra_args) cmd_args_encoded = encode_commandline(pCmdLine);
? (AVAILABLE(jvm_extra_args)
? awprintf(NOT_EMPTY(pCmdLine) ? L"\"%ls\" %ls -jar \"%ls\" %ls %ls" : L"\"%ls\" %ls -jar \"%ls\" %ls", java_runtime_path, jvm_extra_args, jarfile_path, cmd_extra_args, pCmdLine) // Build command-line
: awprintf(NOT_EMPTY(pCmdLine) ? L"\"%ls\" -jar \"%ls\" %ls %ls" : L"\"%ls\" -jar \"%ls\" %ls", java_runtime_path, jarfile_path, cmd_extra_args, pCmdLine)) if (AVAILABLE(cmd_extra_args) && (ext_args_encoded = encode_commandline(cmd_extra_args)))
: (AVAILABLE(jvm_extra_args) {
? awprintf(NOT_EMPTY(pCmdLine) ? L"\"%ls\" %ls -jar \"%ls\" %ls" : L"\"%ls\" %ls -jar \"%ls\"", java_runtime_path, jvm_extra_args, jarfile_path, pCmdLine) command_line = AVAILABLE(jvm_extra_args)
: awprintf(NOT_EMPTY(pCmdLine) ? L"\"%ls\" -jar \"%ls\" %ls" : L"\"%ls\" -jar \"%ls\"", java_runtime_path, jarfile_path, pCmdLine)); ? awprintf(NOT_EMPTY(cmd_args_encoded) ? L"\"%ls\" %ls -Dl5j.pid=%u -jar \"%ls\" %ls %ls" : L"\"%ls\" %ls -Dl5j.pid=%u -jar \"%ls\" %ls", java_runtime_path, jvm_extra_args, pid, jarfile_path, ext_args_encoded, cmd_args_encoded)
: awprintf(NOT_EMPTY(cmd_args_encoded) ? L"\"%ls\" -Dl5j.pid=%u -jar \"%ls\" %ls %ls" : L"\"%ls\" -Dl5j.pid=%u -jar \"%ls\" %ls", java_runtime_path, pid, jarfile_path, ext_args_encoded, cmd_args_encoded);
}
else
{
command_line = AVAILABLE(jvm_extra_args)
? awprintf(NOT_EMPTY(cmd_args_encoded) ? L"\"%ls\" %ls -Dl5j.pid=%u -jar \"%ls\" %ls" : L"\"%ls\" %ls -Dl5j.pid=%u -jar \"%ls\"", java_runtime_path, jvm_extra_args, pid, jarfile_path, cmd_args_encoded)
: awprintf(NOT_EMPTY(cmd_args_encoded) ? L"\"%ls\" -Dl5j.pid=%u -jar \"%ls\" %ls" : L"\"%ls\" -Dl5j.pid=%u -jar \"%ls\"", java_runtime_path, pid, jarfile_path, cmd_args_encoded);
}
// Make sure command-line was created
if (!command_line) if (!command_line)
{ {
show_message(hwnd, MB_ICONERROR | MB_TOPMOST, APP_HEADING, L"The Java command-line could not be generated!"); show_message(hwnd, MB_ICONERROR | MB_TOPMOST, APP_HEADING, L"The Java command-line could not be generated!");
@ -1286,6 +1471,8 @@ cleanup:
free((void*)jvm_extra_args); free((void*)jvm_extra_args);
free((void*)cmd_extra_args); free((void*)cmd_extra_args);
free((void*)ext_args_encoded);
free((void*)cmd_args_encoded);
free((void*)command_line); free((void*)command_line);
free((void*)java_runtime_path); free((void*)java_runtime_path);
free((void*)jarfile_path); free((void*)jarfile_path);