cliprdr: add support for long format names

This commit is contained in:
Marc-André Moreau 2011-11-01 01:09:38 -04:00
parent 1f8b2989be
commit 4dbe450e39
6 changed files with 141 additions and 41 deletions

View File

@ -21,9 +21,10 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <freerdp/constants.h>
#include <freerdp/types.h> #include <freerdp/types.h>
#include <freerdp/constants.h>
#include <freerdp/utils/memory.h> #include <freerdp/utils/memory.h>
#include <freerdp/utils/unicode.h>
#include <freerdp/utils/svc_plugin.h> #include <freerdp/utils/svc_plugin.h>
#include <freerdp/plugins/cliprdr.h> #include <freerdp/plugins/cliprdr.h>
@ -38,8 +39,8 @@
void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIST_EVENT* cb_event) void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIST_EVENT* cb_event)
{ {
STREAM* s;
int i; int i;
STREAM* s;
if (cb_event->raw_format_data) if (cb_event->raw_format_data)
{ {
@ -78,28 +79,107 @@ void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIS
static void cliprdr_send_format_list_response(cliprdrPlugin* cliprdr) static void cliprdr_send_format_list_response(cliprdrPlugin* cliprdr)
{ {
STREAM* s; STREAM* s;
s = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE, CB_RESPONSE_OK, 0); s = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE, CB_RESPONSE_OK, 0);
cliprdr_packet_send(cliprdr, s); cliprdr_packet_send(cliprdr, s);
} }
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen) void cliprdr_process_short_format_names(cliprdrPlugin* cliprdr, STREAM* s, uint32 length, uint16 flags)
{
boolean ascii;
int num_formats;
uint8* end_mark;
CLIPRDR_FORMAT_NAME* format_name;
num_formats = length / 36;
if (num_formats * 36 != length)
DEBUG_WARN("dataLen %d not divided by 36!", length);
ascii = (flags & CB_ASCII_NAMES) ? True : False;
stream_get_mark(s, end_mark);
end_mark += length;
cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) xmalloc(sizeof(CLIPRDR_FORMAT_NAME) * num_formats);
cliprdr->num_format_names = num_formats;
format_name = cliprdr->format_names;
while (s->p < end_mark)
{
stream_read_uint32(s, format_name->id);
if (ascii)
{
format_name->name = xstrdup((char*) s->p);
format_name->length = strlen(format_name->name);
}
else
{
format_name->name = freerdp_uniconv_in(cliprdr->uniconv, s->p, 32);
format_name->length = strlen(format_name->name);
}
stream_seek(s, 32);
format_name++;
}
}
void cliprdr_process_long_format_names(cliprdrPlugin* cliprdr, STREAM* s, uint32 length, uint16 flags)
{
int num_formats;
uint8* start_mark;
uint8* end_mark;
uint16 terminator;
CLIPRDR_FORMAT_NAME* format_name;
num_formats = 0;
stream_get_mark(s, start_mark);
stream_get_mark(s, end_mark);
end_mark += length;
while (s->p < end_mark)
{
stream_seek_uint32(s);
do
{
stream_read_uint16(s, terminator);
}
while (terminator != 0x0000);
num_formats++;
}
stream_set_mark(s, start_mark);
cliprdr->format_names = (CLIPRDR_FORMAT_NAME*) xmalloc(sizeof(CLIPRDR_FORMAT_NAME) * num_formats);
cliprdr->num_format_names = num_formats;
format_name = cliprdr->format_names;
while (s->p < end_mark)
{
stream_read_uint32(s, format_name->id);
format_name->name = freerdp_uniconv_in(cliprdr->uniconv, s->p, 32);
format_name->length = strlen(format_name->name);
stream_seek(s, format_name->length);
format_name++;
}
}
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen, uint16 msgFlags)
{ {
int i; int i;
uint32 format; uint32 format;
int num_formats;
boolean supported; boolean supported;
CLIPRDR_FORMAT_NAME* format_name;
RDP_CB_FORMAT_LIST_EVENT* cb_event; RDP_CB_FORMAT_LIST_EVENT* cb_event;
cb_event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, cb_event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR,
RDP_EVENT_TYPE_CB_FORMAT_LIST, NULL, NULL); RDP_EVENT_TYPE_CB_FORMAT_LIST, NULL, NULL);
/* TODO: support long format names */
num_formats = dataLen / 36;
cb_event->formats = (uint32*) xmalloc(sizeof(uint32) * num_formats);
cb_event->num_formats = 0;
if (dataLen > 0) if (dataLen > 0)
{ {
cb_event->raw_format_data = (uint8*) xmalloc(dataLen); cb_event->raw_format_data = (uint8*) xmalloc(dataLen);
@ -107,13 +187,19 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataL
cb_event->raw_format_data_size = dataLen; cb_event->raw_format_data_size = dataLen;
} }
if (num_formats * 36 != dataLen) if (cliprdr->use_long_format_names)
DEBUG_WARN("dataLen %d not divided by 36!", dataLen); cliprdr_process_long_format_names(cliprdr, s, dataLen, msgFlags);
else
cliprdr_process_short_format_names(cliprdr, s, dataLen, msgFlags);
for (i = 0; i < num_formats; i++) format_name = cliprdr->format_names;
cb_event->num_formats = cliprdr->num_format_names;
cb_event->formats = (uint32*) xmalloc(sizeof(uint32) * cb_event->num_formats);
for (i = 0; i < cliprdr->num_format_names; i++)
{ {
supported = True; supported = True;
stream_read_uint32(s, format); format = format_name->id;
switch (format) switch (format)
{ {
@ -123,22 +209,22 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataL
break; break;
default: default:
if (memcmp(stream_get_tail(s), CFSTR_HTML, sizeof(CFSTR_HTML)) == 0) if (strcmp(format_name->name, "HTML Format") == 0)
{ {
format = CB_FORMAT_HTML; format = CB_FORMAT_HTML;
break; break;
} }
if (memcmp(stream_get_tail(s), CFSTR_PNG, sizeof(CFSTR_PNG)) == 0) if (strcmp(format_name->name, "PNG") == 0)
{ {
format = CB_FORMAT_PNG; format = CB_FORMAT_PNG;
break; break;
} }
if (memcmp(stream_get_tail(s), CFSTR_JPEG, sizeof(CFSTR_JPEG)) == 0) if (strcmp(format_name->name, "JFIF") == 0)
{ {
format = CB_FORMAT_JPEG; format = CB_FORMAT_JPEG;
break; break;
} }
if (memcmp(stream_get_tail(s), CFSTR_GIF, sizeof(CFSTR_GIF)) == 0) if (strcmp(format_name->name, "GIF") == 0)
{ {
format = CB_FORMAT_GIF; format = CB_FORMAT_GIF;
break; break;
@ -147,10 +233,11 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataL
supported = False; supported = False;
break; break;
} }
stream_seek(s, 32);
if (supported) if (supported)
cb_event->formats[cb_event->num_formats++] = format; cb_event->formats[cb_event->num_formats++] = format;
format_name++;
} }
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (RDP_EVENT*) cb_event); svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (RDP_EVENT*) cb_event);
@ -172,11 +259,11 @@ void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, STREAM* s)
{ {
RDP_CB_DATA_REQUEST_EVENT* cb_event; RDP_CB_DATA_REQUEST_EVENT* cb_event;
cb_event = (RDP_CB_DATA_REQUEST_EVENT*)freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, cb_event = (RDP_CB_DATA_REQUEST_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR,
RDP_EVENT_TYPE_CB_DATA_REQUEST, NULL, NULL); RDP_EVENT_TYPE_CB_DATA_REQUEST, NULL, NULL);
stream_read_uint32(s, cb_event->format); stream_read_uint32(s, cb_event->format);
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (RDP_EVENT*)cb_event); svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (RDP_EVENT*) cb_event);
} }
void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_RESPONSE_EVENT* cb_event) void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_RESPONSE_EVENT* cb_event)
@ -199,7 +286,6 @@ void cliprdr_process_format_data_response_event(cliprdrPlugin* cliprdr, RDP_CB_D
void cliprdr_process_format_data_request_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_REQUEST_EVENT* cb_event) void cliprdr_process_format_data_request_event(cliprdrPlugin* cliprdr, RDP_CB_DATA_REQUEST_EVENT* cb_event)
{ {
STREAM* s; STREAM* s;
s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, 0, 4); s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, 0, 4);
stream_write_uint32(s, cb_event->format); stream_write_uint32(s, cb_event->format);
cliprdr_packet_send(cliprdr, s); cliprdr_packet_send(cliprdr, s);
@ -215,7 +301,7 @@ void cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, STREAM* s, uin
if (dataLen > 0) if (dataLen > 0)
{ {
cb_event->size = dataLen; cb_event->size = dataLen;
cb_event->data = (uint8*)xmalloc(dataLen); cb_event->data = (uint8*) xmalloc(dataLen);
memcpy(cb_event->data, stream_get_tail(s), dataLen); memcpy(cb_event->data, stream_get_tail(s), dataLen);
} }

View File

@ -22,7 +22,7 @@
#define __CLIPRDR_FORMAT_H #define __CLIPRDR_FORMAT_H
void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIST_EVENT* cb_event); void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIST_EVENT* cb_event);
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* data_in, uint32 dataLen); void cliprdr_process_format_list(cliprdrPlugin* cliprdr, STREAM* s, uint32 dataLen, uint16 msgFlags);
void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, uint16 msgFlags); void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, uint16 msgFlags);
void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, STREAM* data_in); void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, STREAM* data_in);

View File

@ -21,9 +21,10 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <freerdp/constants.h>
#include <freerdp/types.h> #include <freerdp/types.h>
#include <freerdp/constants.h>
#include <freerdp/utils/memory.h> #include <freerdp/utils/memory.h>
#include <freerdp/utils/unicode.h>
#include <freerdp/utils/svc_plugin.h> #include <freerdp/utils/svc_plugin.h>
#include <freerdp/plugins/cliprdr.h> #include <freerdp/plugins/cliprdr.h>
@ -77,6 +78,8 @@ void cliprdr_packet_send(cliprdrPlugin* cliprdr, STREAM* s)
static void cliprdr_process_connect(rdpSvcPlugin* plugin) static void cliprdr_process_connect(rdpSvcPlugin* plugin)
{ {
DEBUG_CLIPRDR("connecting"); DEBUG_CLIPRDR("connecting");
((cliprdrPlugin*) plugin)->uniconv = freerdp_uniconv_new();
} }
void cliprdr_print_general_capability_flags(uint32 flags) void cliprdr_print_general_capability_flags(uint32 flags)
@ -203,7 +206,7 @@ static void cliprdr_process_receive(rdpSvcPlugin* plugin, STREAM* s)
break; break;
case CB_FORMAT_LIST: case CB_FORMAT_LIST:
cliprdr_process_format_list(cliprdr, s, dataLen); cliprdr_process_format_list(cliprdr, s, dataLen, msgFlags);
break; break;
case CB_FORMAT_LIST_RESPONSE: case CB_FORMAT_LIST_RESPONSE:

View File

@ -24,15 +24,26 @@
#include <freerdp/utils/debug.h> #include <freerdp/utils/debug.h>
#include <freerdp/utils/stream.h> #include <freerdp/utils/stream.h>
typedef struct cliprdr_plugin cliprdrPlugin; struct _CLIPRDR_FORMAT_NAME
{
uint32 id;
char* name;
int length;
};
typedef struct _CLIPRDR_FORMAT_NAME CLIPRDR_FORMAT_NAME;
struct cliprdr_plugin struct cliprdr_plugin
{ {
rdpSvcPlugin plugin; rdpSvcPlugin plugin;
UNICONV* uniconv;
boolean use_long_format_names; boolean use_long_format_names;
boolean stream_fileclip_enabled; boolean stream_fileclip_enabled;
boolean fileclip_no_file_paths; boolean fileclip_no_file_paths;
boolean can_lock_clipdata; boolean can_lock_clipdata;
CLIPRDR_FORMAT_NAME* format_names;
int num_format_names;
}; };
typedef struct cliprdr_plugin cliprdrPlugin;
STREAM* cliprdr_packet_new(uint16 msgType, uint16 msgFlags, uint32 dataLen); STREAM* cliprdr_packet_new(uint16 msgType, uint16 msgFlags, uint32 dataLen);
void cliprdr_packet_send(cliprdrPlugin* cliprdr, STREAM* data_out); void cliprdr_packet_send(cliprdrPlugin* cliprdr, STREAM* data_out);

View File

@ -249,7 +249,7 @@ static boolean xf_cliprdr_is_self_owned(xfInfo* xfi)
XFree(pid); XFree(pid);
} }
if (cb->owner == None || cb->owner == xfi->window->handle) if (cb->owner == None || cb->owner == xfi->drawable)
return False; return False;
if (result != Success) if (result != Success)
@ -371,11 +371,11 @@ static void xf_cliprdr_send_format_list(xfInfo* xfi)
{ {
xf_cliprdr_send_null_format_list(xfi); xf_cliprdr_send_null_format_list(xfi);
} }
else if (cb->owner != xfi->window->handle) else if (cb->owner != xfi->drawable)
{ {
/* Request the owner for TARGETS, and wait for SelectionNotify event */ /* Request the owner for TARGETS, and wait for SelectionNotify event */
XConvertSelection(xfi->display, cb->clipboard_atom, XConvertSelection(xfi->display, cb->clipboard_atom,
cb->targets[1], cb->property_atom, xfi->window->handle, CurrentTime); cb->targets[1], cb->property_atom, xfi->drawable, CurrentTime);
} }
} }
@ -449,7 +449,7 @@ static void xf_cliprdr_process_cb_data_request_event(xfInfo* xfi, RDP_CB_DATA_RE
XConvertSelection(xfi->display, cb->clipboard_atom, XConvertSelection(xfi->display, cb->clipboard_atom,
cb->format_mappings[i].target_format, cb->property_atom, cb->format_mappings[i].target_format, cb->property_atom,
xfi->window->handle, CurrentTime); xfi->drawable, CurrentTime);
XFlush(xfi->display); XFlush(xfi->display);
/* After this point, we expect a SelectionNotify event from the clipboard owner. */ /* After this point, we expect a SelectionNotify event from the clipboard owner. */
} }
@ -466,7 +466,7 @@ static void xf_cliprdr_get_requested_targets(xfInfo* xfi)
RDP_CB_FORMAT_LIST_EVENT* event; RDP_CB_FORMAT_LIST_EVENT* event;
clipboardContext* cb = (clipboardContext*) xfi->clipboard_context; clipboardContext* cb = (clipboardContext*) xfi->clipboard_context;
XGetWindowProperty(xfi->display, xfi->window->handle, cb->property_atom, XGetWindowProperty(xfi->display, xfi->drawable, cb->property_atom,
0, 200, 0, XA_ATOM, 0, 200, 0, XA_ATOM,
&atom, &format, &len, &bytes_left, &data); &atom, &format, &len, &bytes_left, &data);
@ -707,7 +707,7 @@ static boolean xf_cliprdr_get_requested_data(xfInfo* xfi, Atom target)
return False; return False;
} }
XGetWindowProperty(xfi->display, xfi->window->handle, XGetWindowProperty(xfi->display, xfi->drawable,
cb->property_atom, 0, 0, 0, target, cb->property_atom, 0, 0, 0, target,
&type, &format, &len, &bytes_left, &data); &type, &format, &len, &bytes_left, &data);
@ -749,7 +749,7 @@ static boolean xf_cliprdr_get_requested_data(xfInfo* xfi, Atom target)
DEBUG_X11("INCR finished"); DEBUG_X11("INCR finished");
has_data = True; has_data = True;
} }
else if (XGetWindowProperty(xfi->display, xfi->window->handle, else if (XGetWindowProperty(xfi->display, xfi->drawable,
cb->property_atom, 0, bytes_left, 0, target, cb->property_atom, 0, bytes_left, 0, target,
&type, &format, &len, &dummy, &data) == Success) &type, &format, &len, &dummy, &data) == Success)
{ {
@ -770,7 +770,7 @@ static boolean xf_cliprdr_get_requested_data(xfInfo* xfi, Atom target)
DEBUG_X11("XGetWindowProperty failed"); DEBUG_X11("XGetWindowProperty failed");
} }
} }
XDeleteProperty(xfi->display, xfi->window->handle, cb->property_atom); XDeleteProperty(xfi->display, xfi->drawable, cb->property_atom);
xf_cliprdr_process_requested_data(xfi, has_data, data, (int) bytes_left); xf_cliprdr_process_requested_data(xfi, has_data, data, (int) bytes_left);
@ -856,7 +856,7 @@ static void xf_cliprdr_process_cb_format_list_event(xfInfo* xfi, RDP_CB_FORMAT_L
} }
} }
XSetSelectionOwner(xfi->display, cb->clipboard_atom, xfi->window->handle, CurrentTime); XSetSelectionOwner(xfi->display, cb->clipboard_atom, xfi->drawable, CurrentTime);
if (event->raw_format_data) if (event->raw_format_data)
{ {
XChangeProperty(xfi->display, cb->root_window, cb->property_atom, XChangeProperty(xfi->display, cb->root_window, cb->property_atom,
@ -1083,7 +1083,7 @@ boolean xf_cliprdr_process_selection_request(xfInfo* xfi, XEvent* xevent)
DEBUG_X11("target=%d", (int)xevent->xselectionrequest.target); DEBUG_X11("target=%d", (int)xevent->xselectionrequest.target);
if (xevent->xselectionrequest.owner != xfi->window->handle) if (xevent->xselectionrequest.owner != xfi->drawable)
{ {
DEBUG_X11("not owner"); DEBUG_X11("not owner");
return False; return False;
@ -1112,7 +1112,7 @@ boolean xf_cliprdr_process_selection_request(xfInfo* xfi, XEvent* xevent)
else else
{ {
i = xf_cliprdr_select_format_by_atom(cb, xevent->xselectionrequest.target); i = xf_cliprdr_select_format_by_atom(cb, xevent->xselectionrequest.target);
if (i >= 0 && xevent->xselectionrequest.requestor != xfi->window->handle) if (i >= 0 && xevent->xselectionrequest.requestor != xfi->drawable)
{ {
format = cb->format_mappings[i].format_id; format = cb->format_mappings[i].format_id;
alt_format = format; alt_format = format;
@ -1198,7 +1198,7 @@ boolean xf_cliprdr_process_property_notify(xfInfo* xfi, XEvent* xevent)
DEBUG_X11("root window PropertyNotify"); DEBUG_X11("root window PropertyNotify");
xf_cliprdr_send_format_list(xfi); xf_cliprdr_send_format_list(xfi);
} }
else if (xevent->xproperty.window == xfi->window->handle && else if (xevent->xproperty.window == xfi->drawable &&
xevent->xproperty.state == PropertyNewValue && xevent->xproperty.state == PropertyNewValue &&
cb->incr_starts && cb->request_index >= 0) cb->incr_starts && cb->request_index >= 0)
{ {

View File

@ -25,7 +25,7 @@
/* Convert pin/in_len from WINDOWS_CODEPAGE - return like xstrdup, 0-terminated */ /* Convert pin/in_len from WINDOWS_CODEPAGE - return like xstrdup, 0-terminated */
char* freerdp_uniconv_in(UNICONV *uniconv, unsigned char* pin, size_t in_len) char* freerdp_uniconv_in(UNICONV* uniconv, unsigned char* pin, size_t in_len)
{ {
unsigned char *conv_pin = pin; unsigned char *conv_pin = pin;
size_t conv_in_len = in_len; size_t conv_in_len = in_len;