From ef6e4c0570541d3c885ac266d6f1fabf35af6012 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 12 Apr 2021 10:38:40 +0200 Subject: [PATCH] ADDIN_ARGV cleanup, added camera setting to RDP parser (#6947) * Added camerastoredirect to RDP parser * Refactored ADDIN_ARGV handling * Added ADDIN_ARGV unit tests --- client/common/cmdline.c | 82 ++---- client/common/compatibility.c | 65 ++--- client/common/file.c | 79 +++--- include/freerdp/client/cmdline.h | 2 + include/freerdp/settings.h | 31 ++- libfreerdp/common/settings.c | 308 +++++++++++++--------- libfreerdp/common/test/CMakeLists.txt | 1 + libfreerdp/common/test/TestAddinArgv.c | 348 +++++++++++++++++++++++++ winpr/include/winpr/cmdline.h | 2 + winpr/libwinpr/utils/cmdline.c | 30 +++ 10 files changed, 663 insertions(+), 285 deletions(-) create mode 100644 libfreerdp/common/test/TestAddinArgv.c diff --git a/client/common/cmdline.c b/client/common/cmdline.c index f19469e08..13329f425 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -746,9 +746,13 @@ BOOL freerdp_client_add_device_channel(rdpSettings* settings, size_t count, char return FALSE; } +BOOL freerdp_client_del_static_channel(rdpSettings* settings, const char* name) +{ + return freerdp_static_channel_collection_del(settings, name); +} + BOOL freerdp_client_add_static_channel(rdpSettings* settings, size_t count, char** params) { - int index; ADDIN_ARGV* args; if (!settings || !params || !params[0] || (count > INT_MAX)) @@ -757,49 +761,27 @@ BOOL freerdp_client_add_static_channel(rdpSettings* settings, size_t count, char if (freerdp_static_channel_collection_find(settings, params[0])) return TRUE; - args = (ADDIN_ARGV*)calloc(1, sizeof(ADDIN_ARGV)); + args = freerdp_addin_argv_new(count, (const char**)params); if (!args) return FALSE; - args->argc = (int)count; - args->argv = (char**)calloc((size_t)args->argc, sizeof(char*)); - - if (!args->argv) - goto error_argv; - - for (index = 0; index < args->argc; index++) - { - args->argv[index] = _strdup(params[index]); - - if (!args->argv[index]) - { - for (--index; index >= 0; --index) - free(args->argv[index]); - - goto error_argv_strdup; - } - } - if (!freerdp_static_channel_collection_add(settings, args)) - goto error_argv_index; + goto fail; return TRUE; -error_argv_index: - - for (index = 0; index < args->argc; index++) - free(args->argv[index]); - -error_argv_strdup: - free(args->argv); -error_argv: - free(args); +fail: + freerdp_addin_argv_free(args); return FALSE; } +BOOL freerdp_client_del_dynamic_channel(rdpSettings* settings, const char* name) +{ + return freerdp_dynamic_channel_collection_del(settings, name); +} + BOOL freerdp_client_add_dynamic_channel(rdpSettings* settings, size_t count, char** params) { - int index; ADDIN_ARGV* args; if (!settings || !params || !params[0] || (count > INT_MAX)) @@ -808,43 +790,18 @@ BOOL freerdp_client_add_dynamic_channel(rdpSettings* settings, size_t count, cha if (freerdp_dynamic_channel_collection_find(settings, params[0])) return TRUE; - args = (ADDIN_ARGV*)malloc(sizeof(ADDIN_ARGV)); + args = freerdp_addin_argv_new(count, (const char**)params); if (!args) return FALSE; - args->argc = (int)count; - args->argv = (char**)calloc((size_t)args->argc, sizeof(char*)); - - if (!args->argv) - goto error_argv; - - for (index = 0; index < args->argc; index++) - { - args->argv[index] = _strdup(params[index]); - - if (!args->argv[index]) - { - for (--index; index >= 0; --index) - free(args->argv[index]); - - goto error_argv_strdup; - } - } - if (!freerdp_dynamic_channel_collection_add(settings, args)) - goto error_argv_index; + goto fail; return TRUE; -error_argv_index: - for (index = 0; index < args->argc; index++) - free(args->argv[index]); - -error_argv_strdup: - free(args->argv); -error_argv: - free(args); +fail: + freerdp_addin_argv_free(args); return FALSE; } @@ -3503,7 +3460,6 @@ static BOOL freerdp_client_load_static_channel_addin(rdpChannels* channels, rdpS BOOL freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings) { UINT32 index; - ADDIN_ARGV* args; if (settings->AudioPlayback) { @@ -3750,7 +3706,7 @@ BOOL freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings) for (index = 0; index < settings->StaticChannelCount; index++) { - args = settings->StaticChannelArray[index]; + ADDIN_ARGV* args = settings->StaticChannelArray[index]; if (!freerdp_client_load_static_channel_addin(channels, settings, args->argv[0], args)) return FALSE; diff --git a/client/common/compatibility.c b/client/common/compatibility.c index b9b70c893..8f1e7e3f3 100644 --- a/client/common/compatibility.c +++ b/client/common/compatibility.c @@ -291,7 +291,6 @@ static int freerdp_client_old_command_line_pre_filter(void* context, int index, char *a, *p; int i, j, t; int old_index; - ADDIN_ARGV* args; old_index = index; index++; t = index; @@ -299,20 +298,7 @@ static int freerdp_client_old_command_line_pre_filter(void* context, int index, if (index == argc) return -1; - args = (ADDIN_ARGV*)malloc(sizeof(ADDIN_ARGV)); - if (!args) - return -1; - - args->argv = (char**)calloc(argc, sizeof(char*)); - - if (!args->argv) - { - free(args); - return -1; - } - - args->argc = 1; if ((index < argc - 1) && strcmp("--data", argv[index + 1]) == 0) { @@ -321,13 +307,15 @@ static int freerdp_client_old_command_line_pre_filter(void* context, int index, while ((index < argc) && (strcmp("--", argv[index]) != 0)) { - args_handled++; - args->argc = 1; + ADDIN_ARGV* args = freerdp_addin_argv_new(0, NULL); - if (!(args->argv[0] = _strdup(argv[t]))) + if (!args) + return -1; + args_handled++; + + if (!freerdp_addin_argv_add_argument(args, argv[t])) { - free(args->argv); - free(args); + freerdp_addin_argv_free(args); return -1; } @@ -355,34 +343,22 @@ static int freerdp_client_old_command_line_pre_filter(void* context, int index, { length = (int)(p - a); - if (!(args->argv[j + 1] = (char*)malloc(length + 1))) + if (!freerdp_addin_argv_add_argument_ex(args, a, length)) { - for (; j >= 0; --j) - free(args->argv[j]); - - free(args->argv); - free(args); + freerdp_addin_argv_free(args); return -1; } - CopyMemory(args->argv[j + 1], a, length); - args->argv[j + 1][length] = '\0'; p++; } else { - if (!(args->argv[j + 1] = _strdup(a))) + if (!freerdp_addin_argv_add_argument(args, a)) { - for (; j >= 0; --j) - free(args->argv[j]); - - free(args->argv); - free(args); + freerdp_addin_argv_free(args); return -1; } } - - args->argc++; } if (settings) @@ -390,10 +366,7 @@ static int freerdp_client_old_command_line_pre_filter(void* context, int index, freerdp_client_old_process_plugin(settings, args); } - for (j = 0; j < args->argc; j++) - free(args->argv[j]); - - memset(args->argv, 0, argc * sizeof(char*)); + freerdp_addin_argv_free(args); index++; i++; } @@ -402,20 +375,22 @@ static int freerdp_client_old_command_line_pre_filter(void* context, int index, { if (settings) { - if (!(args->argv[0] = _strdup(argv[t]))) + ADDIN_ARGV* args = freerdp_addin_argv_new(0, NULL); + + if (!args) + return -1; + + if (!freerdp_addin_argv_add_argument(args, argv[t])) { - free(args->argv); - free(args); + freerdp_addin_argv_free(args); return -1; } args_handled = freerdp_client_old_process_plugin(settings, args); - free(args->argv[0]); + freerdp_addin_argv_free(args); } } - free(args->argv); - free(args); return (index - old_index) + args_handled; } diff --git a/client/common/file.c b/client/common/file.c index 409da2c3c..6fb976f46 100644 --- a/client/common/file.c +++ b/client/common/file.c @@ -136,6 +136,7 @@ struct rdp_file DWORD RedirectPrinters; /* redirectprinters */ DWORD RedirectComPorts; /* redirectcomports */ DWORD RedirectSmartCards; /* redirectsmartcards */ + LPSTR RedirectCameras; /* camerastoredirect */ DWORD RedirectClipboard; /* redirectclipboard */ DWORD RedirectPosDevices; /* redirectposdevices */ DWORD RedirectDirectX; /* redirectdirectx */ @@ -195,9 +196,7 @@ struct rdp_file size_t lineSize; rdpFileLine* lines; - size_t argc; - char** argv; - size_t argSize; + ADDIN_ARGV* args; void* context; DWORD flags; @@ -431,6 +430,8 @@ static int freerdp_client_rdp_file_set_string(rdpFile* file, const char* name, c tmp = &file->AlternateFullAddress; else if (_stricmp(name, "usbdevicestoredirect") == 0) tmp = &file->UsbDevicesToRedirect; + else if (_stricmp(name, "camerastoredirect") == 0) + tmp = &file->RedirectCameras; else if (_stricmp(name, "loadbalanceinfo") == 0) tmp = &file->LoadBalanceInfo; else if (_stricmp(name, "remoteapplicationname") == 0) @@ -498,27 +499,7 @@ static int freerdp_client_rdp_file_set_string(rdpFile* file, const char* name, c static BOOL freerdp_client_add_option(rdpFile* file, const char* option) { - while ((file->argc + 1) > file->argSize) - { - size_t new_size; - char** new_argv; - new_size = file->argSize * 2; - new_argv = (char**)realloc(file->argv, new_size * sizeof(char*)); - - if (!new_argv) - return FALSE; - - file->argv = new_argv; - file->argSize = new_size; - } - - file->argv[file->argc] = _strdup(option); - - if (!file->argv[file->argc]) - return FALSE; - - (file->argc)++; - return TRUE; + return freerdp_addin_argv_add_argument(file->args, option); } static SSIZE_T freerdp_client_parse_rdp_file_add_line(rdpFile* file, const char* line, @@ -625,6 +606,8 @@ static BOOL trim_strings(rdpFile* file) return FALSE; if (!trim(&file->UsbDevicesToRedirect)) return FALSE; + if (!trim(&file->RedirectCameras)) + return FALSE; if (!trim(&file->LoadBalanceInfo)) return FALSE; if (!trim(&file->GatewayHostname)) @@ -858,6 +841,15 @@ BOOL freerdp_client_parse_rdp_file_ex(rdpFile* file, const char* name, rdp_file_ } \ } while (0) +static char* freerdp_client_channel_args_to_string(const rdpSettings* settings, const char* channel) +{ + ADDIN_ARGV* args = freerdp_dynamic_channel_collection_find(settings, channel); + if (!args || (args->argc < 2)) + return NULL; + + return CommandLineToCommaSeparatedValues(args->argc - 1, args->argv + 1); +} + BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, const rdpSettings* settings) { FILE_POPULATE_STRING(file->Domain, settings->Domain); @@ -948,6 +940,7 @@ BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, const rdpSett file->NetworkAutoDetect = settings->NetworkAutoDetect ? 0 : 1; file->AutoReconnectionEnabled = settings->AutoReconnectionEnabled; file->RedirectSmartCards = settings->RedirectSmartCards; + file->RedirectCameras = freerdp_client_channel_args_to_string(settings, "rdpecam"); file->RedirectClipboard = settings->RedirectClipboard; file->RedirectPrinters = settings->RedirectPrinters; file->RedirectDrives = settings->RedirectDrives; @@ -1171,6 +1164,7 @@ size_t freerdp_client_write_rdp_file_buffer(const rdpFile* file, char* buffer, s WRITE_SETTING_STR("full address:s:%s", file->FullAddress); WRITE_SETTING_STR("alternate full address:s:%s", file->AlternateFullAddress); WRITE_SETTING_STR("usbdevicestoredirect:s:%s", file->UsbDevicesToRedirect); + WRITE_SETTING_STR("camerastoredirect:s:%s", file->RedirectCameras); WRITE_SETTING_STR("loadbalanceinfo:s:%s", file->LoadBalanceInfo); WRITE_SETTING_STR("remoteapplicationname:s:%s", file->RemoteApplicationName); WRITE_SETTING_STR("remoteapplicationicon:s:%s", file->RemoteApplicationIcon); @@ -1800,6 +1794,17 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* return FALSE; } + if (~((size_t)file->RedirectCameras)) + { + BOOL status; + char** p; + size_t count; + p = CommandLineParseCommaSeparatedValuesEx("rdpecam", file->RedirectCameras, &count); + status = freerdp_client_add_dynamic_channel(settings, count, p); + free(p); + /* Ignore return */ WINPR_UNUSED(status); + } + if (~file->KeyboardHook) { if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardHook, file->KeyboardHook)) @@ -1814,13 +1819,13 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* return FALSE; } - if (file->argc > 1) + if (file->args->argc > 1) { char* ConnectionFile = settings->ConnectionFile; settings->ConnectionFile = NULL; - if (freerdp_client_settings_parse_command_line(settings, (int)file->argc, file->argv, - FALSE) < 0) + if (freerdp_client_settings_parse_command_line(settings, (int)file->args->argc, + file->args->argv, FALSE) < 0) return FALSE; settings->ConnectionFile = ConnectionFile; @@ -2020,21 +2025,14 @@ rdpFile* freerdp_client_rdp_file_new_ex(DWORD flags) file->flags = flags; FillMemory(file, sizeof(rdpFile), 0xFF); - file->argv = NULL; file->lines = NULL; file->lineCount = 0; file->lineSize = 32; file->GatewayProfileUsageMethod = 1; file->lines = (rdpFileLine*)calloc(file->lineSize, sizeof(rdpFileLine)); - if (!file->lines) - goto fail; - - file->argc = 0; - file->argSize = 32; - file->argv = (char**)calloc(file->argSize, sizeof(char*)); - - if (!file->argv) + file->args = freerdp_addin_argv_new(0, NULL); + if (!file->lines || !file->args) goto fail; if (!freerdp_client_add_option(file, "freerdp")) @@ -2061,13 +2059,7 @@ void freerdp_client_rdp_file_free(rdpFile* file) } free(file->lines); - if (file->argv) - { - size_t i; - for (i = 0; i < file->argc; i++) - free(file->argv[i]); - } - free(file->argv); + freerdp_addin_argv_free(file->args); freerdp_client_file_string_check_free(file->Username); freerdp_client_file_string_check_free(file->Domain); @@ -2075,6 +2067,7 @@ void freerdp_client_rdp_file_free(rdpFile* file) freerdp_client_file_string_check_free(file->FullAddress); freerdp_client_file_string_check_free(file->AlternateFullAddress); freerdp_client_file_string_check_free(file->UsbDevicesToRedirect); + freerdp_client_file_string_check_free(file->RedirectCameras); freerdp_client_file_string_check_free(file->LoadBalanceInfo); freerdp_client_file_string_check_free(file->RemoteApplicationName); freerdp_client_file_string_check_free(file->RemoteApplicationIcon); diff --git a/include/freerdp/client/cmdline.h b/include/freerdp/client/cmdline.h index a2bc599a9..6f129e05c 100644 --- a/include/freerdp/client/cmdline.h +++ b/include/freerdp/client/cmdline.h @@ -54,8 +54,10 @@ extern "C" char** params); FREERDP_API BOOL freerdp_client_add_static_channel(rdpSettings* settings, size_t count, char** params); + FREERDP_API BOOL freerdp_client_del_static_channel(rdpSettings* settings, const char* name); FREERDP_API BOOL freerdp_client_add_dynamic_channel(rdpSettings* settings, size_t count, char** params); + FREERDP_API BOOL freerdp_client_del_dynamic_channel(rdpSettings* settings, const char* name); #ifdef __cplusplus } diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 97d9ddcbf..08e175585 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -1608,12 +1608,22 @@ extern "C" FREERDP_API void freerdp_settings_dump(wLog* log, DWORD level, const rdpSettings* settings); - FREERDP_API int freerdp_addin_set_argument(ADDIN_ARGV* args, char* argument); - FREERDP_API int freerdp_addin_replace_argument(ADDIN_ARGV* args, char* previous, - char* argument); - FREERDP_API int freerdp_addin_set_argument_value(ADDIN_ARGV* args, char* option, char* value); - FREERDP_API int freerdp_addin_replace_argument_value(ADDIN_ARGV* args, char* previous, - char* option, char* value); + FREERDP_API ADDIN_ARGV* freerdp_addin_argv_new(size_t argc, const char* argv[]); + FREERDP_API ADDIN_ARGV* freerdp_addin_argv_clone(const ADDIN_ARGV* args); + FREERDP_API void freerdp_addin_argv_free(ADDIN_ARGV* args); + + FREERDP_API BOOL freerdp_addin_argv_add_argument(ADDIN_ARGV* args, const char* argument); + FREERDP_API BOOL freerdp_addin_argv_add_argument_ex(ADDIN_ARGV* args, const char* argument, + size_t len); + FREERDP_API BOOL freerdp_addin_argv_del_argument(ADDIN_ARGV* args, const char* argument); + + FREERDP_API int freerdp_addin_set_argument(ADDIN_ARGV* args, const char* argument); + FREERDP_API int freerdp_addin_replace_argument(ADDIN_ARGV* args, const char* previous, + const char* argument); + FREERDP_API int freerdp_addin_set_argument_value(ADDIN_ARGV* args, const char* option, + const char* value); + FREERDP_API int freerdp_addin_replace_argument_value(ADDIN_ARGV* args, const char* previous, + const char* option, const char* value); FREERDP_API BOOL freerdp_device_collection_add(rdpSettings* settings, RDPDR_DEVICE* device); FREERDP_API RDPDR_DEVICE* freerdp_device_collection_find(rdpSettings* settings, @@ -1625,16 +1635,21 @@ extern "C" FREERDP_API BOOL freerdp_static_channel_collection_add(rdpSettings* settings, ADDIN_ARGV* channel); + FREERDP_API BOOL freerdp_static_channel_collection_del(rdpSettings* settings, const char* name); FREERDP_API ADDIN_ARGV* freerdp_static_channel_collection_find(rdpSettings* settings, const char* name); - FREERDP_API ADDIN_ARGV* freerdp_static_channel_clone(ADDIN_ARGV* channel); + FREERDP_API WINPR_DEPRECATED(ADDIN_ARGV* freerdp_static_channel_clone(ADDIN_ARGV* channel)); + FREERDP_API void freerdp_static_channel_collection_free(rdpSettings* settings); FREERDP_API BOOL freerdp_dynamic_channel_collection_add(rdpSettings* settings, ADDIN_ARGV* channel); + FREERDP_API BOOL freerdp_dynamic_channel_collection_del(rdpSettings* settings, + const char* name); FREERDP_API ADDIN_ARGV* freerdp_dynamic_channel_collection_find(rdpSettings* settings, const char* name); - FREERDP_API ADDIN_ARGV* freerdp_dynamic_channel_clone(ADDIN_ARGV* channel); + + FREERDP_API WINPR_DEPRECATED(ADDIN_ARGV* freerdp_dynamic_channel_clone(ADDIN_ARGV* channel)); FREERDP_API void freerdp_dynamic_channel_collection_free(rdpSettings* settings); FREERDP_API void freerdp_target_net_addresses_free(rdpSettings* settings); diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index 6877bbdde..4d391ceea 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -37,10 +37,63 @@ #define TAG FREERDP_TAG("common") -int freerdp_addin_set_argument(ADDIN_ARGV* args, char* argument) +BOOL freerdp_addin_argv_add_argument_ex(ADDIN_ARGV* args, const char* argument, size_t len) +{ + char* str; + char** new_argv; + + if (!args || !argument) + return FALSE; + + if (len == 0) + len = strlen(argument); + + new_argv = (char**)realloc(args->argv, sizeof(char*) * (args->argc + 1)); + + if (!new_argv) + return FALSE; + + args->argv = new_argv; + + str = calloc(len + 1, sizeof(char)); + if (!str) + return FALSE; + memcpy(str, argument, len); + args->argv[args->argc++] = str; + return TRUE; +} + +BOOL freerdp_addin_argv_add_argument(ADDIN_ARGV* args, const char* argument) +{ + return freerdp_addin_argv_add_argument_ex(args, argument, 0); +} + +BOOL freerdp_addin_argv_del_argument(ADDIN_ARGV* args, const char* argument) +{ + int x; + if (!args || !argument) + return FALSE; + for (x = 0; x < args->argc; x++) + { + char* arg = args->argv[x]; + if (strcmp(argument, arg) == 0) + { + free(arg); + memmove_s(&args->argv[x], (args->argc - x) * sizeof(char*), &args->argv[x + 1], + (args->argc - x - 1) * sizeof(char*)); + args->argv[args->argc - 1] = NULL; + args->argc--; + return TRUE; + } + } + return FALSE; +} + +int freerdp_addin_set_argument(ADDIN_ARGV* args, const char* argument) { int i; - char** new_argv; + if (!args || !argument) + return -2; for (i = 0; i < args->argc; i++) { @@ -50,24 +103,17 @@ int freerdp_addin_set_argument(ADDIN_ARGV* args, char* argument) } } - new_argv = (char**)realloc(args->argv, sizeof(char*) * (args->argc + 1)); - - if (!new_argv) + if (!freerdp_addin_argv_add_argument(args, argument)) return -1; - - args->argv = new_argv; - args->argc++; - - if (!(args->argv[args->argc - 1] = _strdup(argument))) - return -1; - return 0; } -int freerdp_addin_replace_argument(ADDIN_ARGV* args, char* previous, char* argument) +int freerdp_addin_replace_argument(ADDIN_ARGV* args, const char* previous, const char* argument) { int i; - char** new_argv; + + if (!args || !previous || !argument) + return -2; for (i = 0; i < args->argc; i++) { @@ -82,29 +128,22 @@ int freerdp_addin_replace_argument(ADDIN_ARGV* args, char* previous, char* argum } } - new_argv = (char**)realloc(args->argv, sizeof(char*) * (args->argc + 1)); - - if (!new_argv) + if (!freerdp_addin_argv_add_argument(args, argument)) return -1; - - args->argv = new_argv; - args->argc++; - - if (!(args->argv[args->argc - 1] = _strdup(argument))) - return -1; - return 0; } -int freerdp_addin_set_argument_value(ADDIN_ARGV* args, char* option, char* value) +int freerdp_addin_set_argument_value(ADDIN_ARGV* args, const char* option, const char* value) { + BOOL rc; int i; char* p; char* str; size_t length; - char** new_argv; + if (!args || !option || !value) + return -2; length = strlen(option) + strlen(value) + 1; - str = (char*)malloc(length + 1); + str = (char*)calloc(length + 1, sizeof(char)); if (!str) return -1; @@ -126,29 +165,24 @@ int freerdp_addin_set_argument_value(ADDIN_ARGV* args, char* option, char* value } } - new_argv = (char**)realloc(args->argv, sizeof(char*) * (args->argc + 1)); - - if (!new_argv) - { - free(str); + rc = freerdp_addin_argv_add_argument(args, str); + free(str); + if (!rc) return -1; - } - - args->argv = new_argv; - args->argc++; - args->argv[args->argc - 1] = str; return 0; } -int freerdp_addin_replace_argument_value(ADDIN_ARGV* args, char* previous, char* option, - char* value) +int freerdp_addin_replace_argument_value(ADDIN_ARGV* args, const char* previous, const char* option, + const char* value) { int i; + BOOL rc; char* str; size_t length; - char** new_argv; + if (!args || !previous || !option || !value) + return -2; length = strlen(option) + strlen(value) + 1; - str = (char*)malloc(length + 1); + str = (char*)calloc(length + 1, sizeof(char)); if (!str) return -1; @@ -165,17 +199,10 @@ int freerdp_addin_replace_argument_value(ADDIN_ARGV* args, char* previous, char* } } - new_argv = (char**)realloc(args->argv, sizeof(char*) * (args->argc + 1)); - - if (!new_argv) - { - free(str); + rc = freerdp_addin_argv_add_argument(args, str); + free(str); + if (!rc) return -1; - } - - args->argv = new_argv; - args->argc++; - args->argv[args->argc - 1] = str; return 0; } @@ -457,6 +484,30 @@ void freerdp_device_collection_free(rdpSettings* settings) settings->DeviceCount = 0; } +BOOL freerdp_static_channel_collection_del(rdpSettings* settings, const char* name) +{ + UINT32 x; + const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_StaticChannelCount); + if (!settings || !settings->StaticChannelArray) + return FALSE; + + for (x = 0; x < count; x++) + { + ADDIN_ARGV* cur = settings->StaticChannelArray[x]; + if (cur && (cur->argc > 0)) + { + if (strcmp(name, cur->argv[0]) == 0) + { + memmove_s(&settings->StaticChannelArray[x], (count - x) * sizeof(ADDIN_ARGV*), + &settings->StaticChannelArray[x + 1], + (count - x - 1) * sizeof(ADDIN_ARGV*)); + return freerdp_settings_set_uint32(settings, FreeRDP_StaticChannelCount, count - 1); + } + } + } + return FALSE; +} + BOOL freerdp_static_channel_collection_add(rdpSettings* settings, ADDIN_ARGV* channel) { UINT32 count; @@ -502,55 +553,13 @@ ADDIN_ARGV* freerdp_static_channel_collection_find(rdpSettings* settings, const return NULL; } -ADDIN_ARGV* freerdp_static_channel_clone(ADDIN_ARGV* channel) -{ - int index; - ADDIN_ARGV* _channel = NULL; - _channel = (ADDIN_ARGV*)malloc(sizeof(ADDIN_ARGV)); - - if (!_channel) - return NULL; - - _channel->argc = channel->argc; - _channel->argv = (char**)calloc(channel->argc, sizeof(char*)); - - if (!_channel->argv) - goto out_free; - - for (index = 0; index < _channel->argc; index++) - { - _channel->argv[index] = _strdup(channel->argv[index]); - - if (!_channel->argv[index]) - goto out_release_args; - } - - return _channel; -out_release_args: - - for (index = 0; _channel->argv[index]; index++) - free(_channel->argv[index]); - -out_free: - free(_channel); - return NULL; -} - void freerdp_static_channel_collection_free(rdpSettings* settings) { - int j; UINT32 i; for (i = 0; i < freerdp_settings_get_uint32(settings, FreeRDP_StaticChannelCount); i++) { - if (!settings->StaticChannelArray[i]) - continue; - - for (j = 0; j < settings->StaticChannelArray[i]->argc; j++) - free(settings->StaticChannelArray[i]->argv[j]); - - free(settings->StaticChannelArray[i]->argv); - free(settings->StaticChannelArray[i]); + freerdp_addin_argv_free(settings->StaticChannelArray[i]); } free(settings->StaticChannelArray); @@ -559,6 +568,32 @@ void freerdp_static_channel_collection_free(rdpSettings* settings) freerdp_settings_set_uint32(settings, FreeRDP_StaticChannelCount, 0); } +BOOL freerdp_dynamic_channel_collection_del(rdpSettings* settings, const char* name) +{ + UINT32 x; + const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_DynamicChannelCount); + if (!settings || !settings->DynamicChannelArray) + return FALSE; + + for (x = 0; x < count; x++) + { + ADDIN_ARGV* cur = settings->DynamicChannelArray[x]; + if (cur && (cur->argc > 0)) + { + if (strcmp(name, cur->argv[0])) + { + memmove_s(&settings->DynamicChannelArray[x], (count - x) * sizeof(ADDIN_ARGV*), + &settings->DynamicChannelArray[x + 1], + (count - x - 1) * sizeof(ADDIN_ARGV*)); + return freerdp_settings_set_uint32(settings, FreeRDP_DynamicChannelCount, + count - 1); + } + } + } + + return FALSE; +} + BOOL freerdp_dynamic_channel_collection_add(rdpSettings* settings, ADDIN_ARGV* channel) { UINT32 count; @@ -603,55 +638,66 @@ ADDIN_ARGV* freerdp_dynamic_channel_collection_find(rdpSettings* settings, const return NULL; } -ADDIN_ARGV* freerdp_dynamic_channel_clone(ADDIN_ARGV* channel) +void freerdp_addin_argv_free(ADDIN_ARGV* args) { int index; - ADDIN_ARGV* _channel = NULL; - _channel = (ADDIN_ARGV*)malloc(sizeof(ADDIN_ARGV)); + if (!args) + return; - if (!_channel) - return NULL; - - _channel->argc = channel->argc; - _channel->argv = (char**)calloc(sizeof(char*), channel->argc); - - if (!_channel->argv) - goto out_free; - - for (index = 0; index < _channel->argc; index++) + if (args->argv) { - _channel->argv[index] = _strdup(channel->argv[index]); - - if (!_channel->argv[index]) - goto out_release_args; + for (index = 0; index < args->argc; index++) + free(args->argv[index]); + free(args->argv); } - return _channel; -out_release_args: + free(args); +} - for (index = 0; _channel->argv[index]; index++) - free(_channel->argv[index]); +ADDIN_ARGV* freerdp_addin_argv_new(size_t argc, const char* argv[]) +{ + ADDIN_ARGV* args = calloc(1, sizeof(ADDIN_ARGV)); + if (!args) + return NULL; + if (argc == 0) + return args; -out_free: - free(_channel); + args->argc = argc; + args->argv = calloc(argc, sizeof(char*)); + if (!args->argv) + goto fail; + + if (argv) + { + size_t x; + for (x = 0; x < argc; x++) + { + args->argv[x] = _strdup(argv[x]); + if (!args->argv[x]) + goto fail; + } + } + return args; + +fail: + freerdp_addin_argv_free(args); return NULL; } +ADDIN_ARGV* freerdp_addin_argv_clone(const ADDIN_ARGV* args) +{ + if (!args) + return NULL; + return freerdp_addin_argv_new(args->argc, (const char**)args->argv); +} + void freerdp_dynamic_channel_collection_free(rdpSettings* settings) { - int j; UINT32 i; for (i = 0; i < freerdp_settings_get_uint32(settings, FreeRDP_DynamicChannelCount); i++) { - if (!settings->DynamicChannelArray[i]) - continue; - - for (j = 0; j < settings->DynamicChannelArray[i]->argc; j++) - free(settings->DynamicChannelArray[i]->argv[j]); - - free(settings->DynamicChannelArray[i]->argv); - free(settings->DynamicChannelArray[i]); + freerdp_addin_argv_free(settings->DynamicChannelArray[i]); } free(settings->DynamicChannelArray); @@ -1210,3 +1256,13 @@ UINT32 freerdp_settings_get_codecs_flags(const rdpSettings* settings) /*TODO: check other codecs flags */ return flags; } + +ADDIN_ARGV* freerdp_static_channel_clone(ADDIN_ARGV* channel) +{ + return freerdp_addin_argv_clone(channel); +} + +ADDIN_ARGV* freerdp_dynamic_channel_clone(ADDIN_ARGV* channel) +{ + return freerdp_addin_argv_clone(channel); +} diff --git a/libfreerdp/common/test/CMakeLists.txt b/libfreerdp/common/test/CMakeLists.txt index 006af97d4..726d11973 100644 --- a/libfreerdp/common/test/CMakeLists.txt +++ b/libfreerdp/common/test/CMakeLists.txt @@ -5,6 +5,7 @@ set(MODULE_PREFIX "TEST_COMMON") set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS + TestAddinArgv.c TestCommonAssistance.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS diff --git a/libfreerdp/common/test/TestAddinArgv.c b/libfreerdp/common/test/TestAddinArgv.c new file mode 100644 index 000000000..729b5668e --- /dev/null +++ b/libfreerdp/common/test/TestAddinArgv.c @@ -0,0 +1,348 @@ +#include +#include + +#include + +static BOOL test_alloc(void) +{ + BOOL rc = FALSE; + int rng, x; + const char* param[] = { "foo:", "bar", "bla", "rdp", NULL }; + ADDIN_ARGV* arg1 = NULL; + ADDIN_ARGV* arg2 = NULL; + ADDIN_ARGV* arg3 = NULL; + ADDIN_ARGV* arg4 = NULL; + + /* Test empty allocation */ + arg1 = freerdp_addin_argv_new(0, NULL); + if (!arg1 || (arg1->argc != 0) || (arg1->argv)) + goto fail; + + /* Test allocation without initializing arguments of random size > 0 */ + winpr_RAND((BYTE*)&rng, sizeof(rng)); + rng = abs(rng % 8192) + 1; + + arg2 = freerdp_addin_argv_new(rng, NULL); + if (!arg2 || (arg2->argc != rng) || (!arg2->argv)) + goto fail; + for (x = 0; x < arg2->argc; x++) + { + if (arg2->argv[x]) + goto fail; + } + + /* Test allocation with initializing arguments of size > 0 */ + arg3 = freerdp_addin_argv_new(ARRAYSIZE(param) - 1, param); + if (!arg3 || (arg3->argc != ARRAYSIZE(param) - 1) || (!arg3->argv)) + goto fail; + + for (x = 0; x < arg3->argc; x++) + { + if (strcmp(arg3->argv[x], param[x]) != 0) + goto fail; + } + + /* Input lists with NULL elements are not allowed */ + arg4 = freerdp_addin_argv_new(ARRAYSIZE(param), param); + if (arg4) + goto fail; + rc = TRUE; +fail: + freerdp_addin_argv_free(arg1); + freerdp_addin_argv_free(arg2); + freerdp_addin_argv_free(arg3); + freerdp_addin_argv_free(arg4); + printf("%s: %d\n", __FUNCTION__, rc); + return rc; +} + +static BOOL test_clone(void) +{ + int x; + BOOL rc = FALSE; + const char* param[] = { "foo:", "bar", "bla", "rdp" }; + ADDIN_ARGV* arg = NULL; + ADDIN_ARGV* clone = NULL; + ADDIN_ARGV* clone2 = NULL; + + arg = freerdp_addin_argv_new(ARRAYSIZE(param), param); + if (!arg || (arg->argc != ARRAYSIZE(param))) + goto fail; + clone = freerdp_addin_argv_clone(arg); + if (!clone || (clone->argc != arg->argc)) + goto fail; + + for (x = 0; x < arg->argc; x++) + { + if (strcmp(param[x], arg->argv[x]) != 0) + goto fail; + if (strcmp(param[x], clone->argv[x]) != 0) + goto fail; + } + + clone2 = freerdp_addin_argv_clone(NULL); + if (clone2) + goto fail; + rc = TRUE; +fail: + freerdp_addin_argv_free(arg); + freerdp_addin_argv_free(clone); + freerdp_addin_argv_free(clone2); + printf("%s: %d\n", __FUNCTION__, rc); + return rc; +} + +static BOOL test_add_remove(void) +{ + size_t x, y; + const char* args[] = { "foo", "bar", "bla", "gaga" }; + BOOL rc = FALSE; + ADDIN_ARGV* arg = NULL; + + arg = freerdp_addin_argv_new(0, NULL); + if (!arg || (arg->argc != 0) || arg->argv) + goto fail; + for (y = 0; y < ARRAYSIZE(args); y++) + { + const char* param = args[y]; + if (!freerdp_addin_argv_add_argument(arg, param)) + goto fail; + if (arg->argc != (int)y + 1) + goto fail; + if (!arg->argv) + goto fail; + if (strcmp(arg->argv[y], param) != 0) + goto fail; + } + + /* Try to remove non existing element, must not return TRUE */ + if (freerdp_addin_argv_del_argument(arg, "foobar")) + goto fail; + + /* Invalid parameters, must return FALSE */ + if (freerdp_addin_argv_del_argument(NULL, "foobar")) + goto fail; + + /* Invalid parameters, must return FALSE */ + if (freerdp_addin_argv_del_argument(arg, NULL)) + goto fail; + + /* Remove elements one by one to test argument index move */ + for (y = 0; y < ARRAYSIZE(args); y++) + { + const char* param = args[y]; + if (!freerdp_addin_argv_del_argument(arg, param)) + goto fail; + for (x = y + 1; x < ARRAYSIZE(args); x++) + { + if (strcmp(arg->argv[x - y - 1], args[x]) != 0) + goto fail; + } + } + rc = TRUE; +fail: + freerdp_addin_argv_free(arg); + printf("%s: %d\n", __FUNCTION__, rc); + return rc; +} + +static BOOL test_set_argument(void) +{ + int ret; + const char* newarg = "foobar"; + const char* args[] = { "foo", "bar", "bla", "gaga" }; + BOOL rc = FALSE; + ADDIN_ARGV* arg = NULL; + + arg = freerdp_addin_argv_new(ARRAYSIZE(args), args); + if (!arg || (arg->argc != ARRAYSIZE(args)) || !arg->argv) + goto fail; + + /* Check invalid parameters */ + ret = freerdp_addin_set_argument(NULL, "foo"); + if (ret >= 0) + goto fail; + ret = freerdp_addin_set_argument(arg, NULL); + if (ret >= 0) + goto fail; + + /* Try existing parameter */ + ret = freerdp_addin_set_argument(arg, "foo"); + if ((ret != 1) || (arg->argc != ARRAYSIZE(args))) + goto fail; + + /* Try new parameter */ + ret = freerdp_addin_set_argument(arg, newarg); + if ((ret != 0) || (arg->argc != ARRAYSIZE(args) + 1) || + (strcmp(newarg, arg->argv[ARRAYSIZE(args)]) != 0)) + goto fail; + + rc = TRUE; +fail: + freerdp_addin_argv_free(arg); + printf("%s: %d\n", __FUNCTION__, rc); + return rc; +} + +static BOOL test_replace_argument(void) +{ + int ret; + const char* newarg = "foobar"; + const char* args[] = { "foo", "bar", "bla", "gaga" }; + BOOL rc = FALSE; + ADDIN_ARGV* arg = NULL; + + arg = freerdp_addin_argv_new(ARRAYSIZE(args), args); + if (!arg || (arg->argc != ARRAYSIZE(args)) || !arg->argv) + goto fail; + + /* Check invalid parameters */ + ret = freerdp_addin_replace_argument(NULL, "foo", newarg); + if (ret >= 0) + goto fail; + ret = freerdp_addin_replace_argument(arg, NULL, newarg); + if (ret >= 0) + goto fail; + ret = freerdp_addin_replace_argument(arg, "foo", NULL); + if (ret >= 0) + goto fail; + + /* Try existing parameter */ + ret = freerdp_addin_replace_argument(arg, "foo", newarg); + if ((ret != 1) || (arg->argc != ARRAYSIZE(args)) || (strcmp(arg->argv[0], newarg) != 0)) + goto fail; + + /* Try new parameter */ + ret = freerdp_addin_replace_argument(arg, "lalala", newarg); + if ((ret != 0) || (arg->argc != ARRAYSIZE(args) + 1) || + (strcmp(newarg, arg->argv[ARRAYSIZE(args)]) != 0)) + goto fail; + + rc = TRUE; +fail: + freerdp_addin_argv_free(arg); + printf("%s: %d\n", __FUNCTION__, rc); + return rc; +} + +static BOOL test_set_argument_value(void) +{ + int ret; + const char* newarg1 = "foobar"; + const char* newarg2 = "lalala"; + const char* fullnewarg1 = "foo:foobar"; + const char* fullnewarg2 = "foo:lalala"; + const char* fullnewvalue = "lalala:foobar"; + const char* args[] = { "foo", "foo:", "bar", "bla", "gaga" }; + BOOL rc = FALSE; + ADDIN_ARGV* arg = NULL; + + arg = freerdp_addin_argv_new(ARRAYSIZE(args), args); + if (!arg || (arg->argc != ARRAYSIZE(args)) || !arg->argv) + goto fail; + + /* Check invalid parameters */ + ret = freerdp_addin_set_argument_value(NULL, "foo", newarg1); + if (ret >= 0) + goto fail; + ret = freerdp_addin_set_argument_value(arg, NULL, newarg1); + if (ret >= 0) + goto fail; + ret = freerdp_addin_set_argument_value(arg, "foo", NULL); + if (ret >= 0) + goto fail; + + /* Try existing parameter */ + ret = freerdp_addin_set_argument_value(arg, "foo", newarg1); + if ((ret != 1) || (arg->argc != ARRAYSIZE(args)) || (strcmp(arg->argv[1], fullnewarg1) != 0)) + goto fail; + ret = freerdp_addin_set_argument_value(arg, "foo", newarg2); + if ((ret != 1) || (arg->argc != ARRAYSIZE(args)) || (strcmp(arg->argv[1], fullnewarg2) != 0)) + goto fail; + + /* Try new parameter */ + ret = freerdp_addin_set_argument_value(arg, newarg2, newarg1); + if ((ret != 0) || (arg->argc != ARRAYSIZE(args) + 1) || + (strcmp(fullnewvalue, arg->argv[ARRAYSIZE(args)]) != 0)) + goto fail; + + rc = TRUE; +fail: + freerdp_addin_argv_free(arg); + printf("%s: %d\n", __FUNCTION__, rc); + return rc; +} + +static BOOL test_replace_argument_value(void) +{ + int ret; + const char* newarg1 = "foobar"; + const char* newarg2 = "lalala"; + const char* fullnewarg1 = "foo:foobar"; + const char* fullnewarg2 = "foo:lalala"; + const char* fullnewvalue = "lalala:foobar"; + const char* args[] = { "foo", "foo:", "bar", "bla", "gaga" }; + BOOL rc = FALSE; + ADDIN_ARGV* arg = NULL; + + arg = freerdp_addin_argv_new(ARRAYSIZE(args), args); + if (!arg || (arg->argc != ARRAYSIZE(args)) || !arg->argv) + goto fail; + + /* Check invalid parameters */ + ret = freerdp_addin_replace_argument_value(NULL, "bar", "foo", newarg1); + if (ret >= 0) + goto fail; + ret = freerdp_addin_replace_argument_value(arg, NULL, "foo", newarg1); + if (ret >= 0) + goto fail; + ret = freerdp_addin_replace_argument_value(arg, "foo", NULL, newarg1); + if (ret >= 0) + goto fail; + ret = freerdp_addin_replace_argument_value(arg, "bar", "foo", NULL); + if (ret >= 0) + goto fail; + + /* Try existing parameter */ + ret = freerdp_addin_replace_argument_value(arg, "bla", "foo", newarg1); + if ((ret != 1) || (arg->argc != ARRAYSIZE(args)) || (strcmp(arg->argv[3], fullnewarg1) != 0)) + goto fail; + ret = freerdp_addin_replace_argument_value(arg, "foo", "foo", newarg2); + if ((ret != 1) || (arg->argc != ARRAYSIZE(args)) || (strcmp(arg->argv[0], fullnewarg2) != 0)) + goto fail; + + /* Try new parameter */ + ret = freerdp_addin_replace_argument_value(arg, "hahaha", newarg2, newarg1); + if ((ret != 0) || (arg->argc != ARRAYSIZE(args) + 1) || + (strcmp(fullnewvalue, arg->argv[ARRAYSIZE(args)]) != 0)) + goto fail; + + rc = TRUE; +fail: + freerdp_addin_argv_free(arg); + printf("%s: %d\n", __FUNCTION__, rc); + return rc; +} + +int TestAddinArgv(int argc, char* argv[]) +{ + + WINPR_UNUSED(argc); + WINPR_UNUSED(argv); + + if (!test_alloc()) + return -1; + if (!test_clone()) + return -1; + if (!test_add_remove()) + return -1; + if (!test_set_argument()) + return -1; + if (!test_replace_argument()) + return -1; + if (!test_set_argument_value()) + return -1; + if (!test_replace_argument_value()) + return -1; + return 0; +} diff --git a/winpr/include/winpr/cmdline.h b/winpr/include/winpr/cmdline.h index 9276cda8e..332fe94c3 100644 --- a/winpr/include/winpr/cmdline.h +++ b/winpr/include/winpr/cmdline.h @@ -165,6 +165,8 @@ extern "C" WINPR_API char** CommandLineParseCommaSeparatedValuesEx(const char* name, const char* list, size_t* count); + WINPR_API char* CommandLineToCommaSeparatedValues(int argc, char* argv[]); + #ifdef __cplusplus } #endif diff --git a/winpr/libwinpr/utils/cmdline.c b/winpr/libwinpr/utils/cmdline.c index 8b9744db0..7153b0dfd 100644 --- a/winpr/libwinpr/utils/cmdline.c +++ b/winpr/libwinpr/utils/cmdline.c @@ -558,3 +558,33 @@ char** CommandLineParseCommaSeparatedValues(const char* list, size_t* count) { return CommandLineParseCommaSeparatedValuesEx(NULL, list, count); } + +char* CommandLineToCommaSeparatedValues(int argc, char* argv[]) +{ + int x; + char* str = NULL; + size_t offset = 0; + size_t size = argc + 1; + if ((argc <= 0) || !argv) + return NULL; + + for (x = 0; x < argc; x++) + size += strlen(argv[x]); + + str = calloc(size, sizeof(char)); + if (!str) + return NULL; + for (x = 0; x < argc; x++) + { + int rc = _snprintf(&str[offset], size - offset, "%s,", argv[x]); + if (rc <= 0) + { + free(str); + return NULL; + } + offset += (size_t)rc; + } + if (offset > 0) + str[offset - 1] = '\0'; + return str; +}