From 7cf5d02019309e0fb4f30aa57cec14b81168fb4b Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 1 Apr 2014 18:41:55 -0700 Subject: [PATCH] GUAC-584: Simplify copy logic. Store clipboard in static 256K buffer. Convert from UTF16 properly. --- src/common/guac_iconv.c | 7 ++- src/common/guac_iconv.h | 4 +- src/protocols/rdp/client.c | 1 - src/protocols/rdp/client.h | 9 +++- src/protocols/rdp/guac_handlers.c | 9 ++-- src/protocols/rdp/rdp_cliprdr.c | 71 ++++++------------------------- 6 files changed, 31 insertions(+), 70 deletions(-) diff --git a/src/common/guac_iconv.c b/src/common/guac_iconv.c index a6fd89d9..0dcab980 100644 --- a/src/common/guac_iconv.c +++ b/src/common/guac_iconv.c @@ -26,7 +26,7 @@ #include #include -void guac_iconv(guac_iconv_read* reader, char** input, int in_remaining, +int guac_iconv(guac_iconv_read* reader, char** input, int in_remaining, guac_iconv_write* writer, char** output, int out_remaining) { while (in_remaining > 0 && out_remaining > 0) { @@ -47,10 +47,13 @@ void guac_iconv(guac_iconv_read* reader, char** input, int in_remaining, /* Stop if null terminator reached */ if (value == 0) - break; + return 1; } + /* Null terminator not reached */ + return 0; + } int GUAC_READ_UTF8(char** input, int remaining) { diff --git a/src/common/guac_iconv.h b/src/common/guac_iconv.h index 1677541c..98cdce7c 100644 --- a/src/common/guac_iconv.h +++ b/src/common/guac_iconv.h @@ -53,8 +53,10 @@ typedef void guac_iconv_write(char** output, int remaining, int value); * @param output Pointer to the beginning of the output string. * @param out_remaining The number of bytes remaining after the pointer to the * output string. + * @return Non-zero if the NULL terminator of the input string was read and + * copied into the destination string, zero otherwise. */ -void guac_iconv(guac_iconv_read* reader, char** input, int in_remaining, +int guac_iconv(guac_iconv_read* reader, char** input, int in_remaining, guac_iconv_write* writer, char** output, int out_remaining); /** diff --git a/src/protocols/rdp/client.c b/src/protocols/rdp/client.c index 40ae2911..0e7fa873 100644 --- a/src/protocols/rdp/client.c +++ b/src/protocols/rdp/client.c @@ -655,7 +655,6 @@ int guac_client_init(guac_client* client, int argc, char** argv) { guac_client_data->bounded = FALSE; guac_client_data->mouse_button_mask = 0; guac_client_data->current_surface = GUAC_DEFAULT_LAYER; - guac_client_data->clipboard = NULL; guac_client_data->requested_clipboard_format = CB_FORMAT_TEXT; guac_client_data->audio = NULL; guac_client_data->filesystem = NULL; diff --git a/src/protocols/rdp/client.h b/src/protocols/rdp/client.h index 2ebb3935..c6d242cb 100644 --- a/src/protocols/rdp/client.h +++ b/src/protocols/rdp/client.h @@ -70,6 +70,11 @@ */ #define GUAC_RDP_REASONABLE_AREA (800*600) +/** + * The maximum number of bytes to allow within the clipboard. + */ +#define GUAC_RDP_CLIPBOARD_MAX_LENGTH 262144 + /** * Client data that will remain accessible through the guac_client. * This should generally include data commonly used by Guacamole handlers. @@ -166,9 +171,9 @@ typedef struct rdp_guac_client_data { guac_rdp_keysym_state_map keysym_state; /** - * The current text (NOT Unicode) clipboard contents. + * The current clipboard contents, in UTF-8. */ - char* clipboard; + char clipboard[GUAC_RDP_CLIPBOARD_MAX_LENGTH]; /** * The format of the clipboard which was requested. Data received from diff --git a/src/protocols/rdp/guac_handlers.c b/src/protocols/rdp/guac_handlers.c index 273e417f..a55dee9a 100644 --- a/src/protocols/rdp/guac_handlers.c +++ b/src/protocols/rdp/guac_handlers.c @@ -462,8 +462,8 @@ int rdp_guac_client_key_handler(guac_client* client, int keysym, int pressed) { int rdp_guac_client_clipboard_handler(guac_client* client, char* data) { - rdpChannels* channels = - ((rdp_guac_client_data*) client->data)->rdp_inst->context->channels; + rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data; + rdpChannels* channels = client_data->rdp_inst->context->channels; RDP_CB_FORMAT_LIST_EVENT* format_list = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new( @@ -471,11 +471,8 @@ int rdp_guac_client_clipboard_handler(guac_client* client, char* data) { CliprdrChannel_FormatList, NULL, NULL); - /* Free existing data */ - free(((rdp_guac_client_data*) client->data)->clipboard); - /* Store data in client */ - ((rdp_guac_client_data*) client->data)->clipboard = strdup(data); + strncpy(client_data->clipboard, data, GUAC_RDP_CLIPBOARD_MAX_LENGTH); /* Notify server that text data is now available */ format_list->formats = (UINT32*) malloc(sizeof(UINT32)); diff --git a/src/protocols/rdp/rdp_cliprdr.c b/src/protocols/rdp/rdp_cliprdr.c index 4f98c17a..24b8fe41 100644 --- a/src/protocols/rdp/rdp_cliprdr.c +++ b/src/protocols/rdp/rdp_cliprdr.c @@ -24,7 +24,7 @@ #include "client.h" #include "rdp_cliprdr.h" -#include "unicode.h" +#include "guac_iconv.h" #include #include @@ -212,76 +212,26 @@ void guac_rdp_process_cb_data_request(guac_client* client, } -static void __guac_rdp_clipboard_send_iso8859_1(guac_client* client, - RDP_CB_DATA_RESPONSE_EVENT* event) { - - rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data; - - /* Ensure data is large enough and has null terminator */ - if (event->size < 1 || event->data[event->size - 1] != '\0') { - guac_client_log_error(client, - "Clipboard data missing null terminator"); - return; - } - - /* Free existing data */ - free(client_data->clipboard); - - /* Store clipboard data */ - client_data->clipboard = strdup((char*) event->data); - - /* Send clipboard data */ - guac_protocol_send_clipboard(client->socket, client_data->clipboard); - -} - -static void __guac_rdp_clipboard_send_utf16(guac_client* client, - RDP_CB_DATA_RESPONSE_EVENT* event) { - - rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data; - int output_length; - - /* Ensure data is large enough and has null terminator */ - if (event->size < 2 - || event->data[event->size - 2] != '\0' - || event->data[event->size - 1] != '\0') { - guac_client_log_error(client, - "Clipboard data missing null terminator"); - return; - } - - /* Free existing data */ - free(client_data->clipboard); - - /* Store clipboard data */ - output_length = event->size * 3; - client_data->clipboard = malloc(output_length); - guac_rdp_utf16_to_utf8(event->data, event->size/2, - client_data->clipboard, output_length); - - /* Send clipboard data */ - guac_protocol_send_clipboard(client->socket, client_data->clipboard); - -} - void guac_rdp_process_cb_data_response(guac_client* client, RDP_CB_DATA_RESPONSE_EVENT* event) { rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data; - /* Convert to UTF-8 based on format */ + guac_iconv_read* reader; + char* input = (char*) event->data; + char* output = client_data->clipboard; + + /* Find correct source encoding */ switch (client_data->requested_clipboard_format) { /* Non-Unicode */ case CB_FORMAT_TEXT: - guac_client_log_info(client, "STUB: Copy non-unicode"); - __guac_rdp_clipboard_send_iso8859_1(client, event); + reader = GUAC_READ_UTF8; break; /* Unicode (UTF-16) */ case CB_FORMAT_UNICODETEXT: - guac_client_log_info(client, "STUB: Copy unicode"); - __guac_rdp_clipboard_send_utf16(client, event); + reader = GUAC_READ_UTF16; break; default: @@ -292,5 +242,10 @@ void guac_rdp_process_cb_data_response(guac_client* client, } + /* Convert send clipboard data */ + if (guac_iconv(reader, &input, event->size, + GUAC_WRITE_UTF8, &output, GUAC_RDP_CLIPBOARD_MAX_LENGTH)) + guac_protocol_send_clipboard(client->socket, client_data->clipboard); + }