xfreerdp: refactor cliprdr helpers

This commit is contained in:
Marc-André Moreau 2014-10-16 15:05:06 -04:00
parent 4111625488
commit d668855be6
1 changed files with 133 additions and 134 deletions

View File

@ -93,7 +93,7 @@ struct xf_clipboard
int xf_cliprdr_send_client_format_list(xfClipboard* clipboard); int xf_cliprdr_send_client_format_list(xfClipboard* clipboard);
static BYTE* lf2crlf(BYTE* data, int* size) static BYTE* ConvertLineEndingToCRLF(BYTE* str, int* size)
{ {
BYTE c; BYTE c;
BYTE* outbuf; BYTE* outbuf;
@ -104,15 +104,15 @@ static BYTE* lf2crlf(BYTE* data, int* size)
out_size = (*size) * 2 + 1; out_size = (*size) * 2 + 1;
outbuf = (BYTE*) malloc(out_size); outbuf = (BYTE*) malloc(out_size);
ZeroMemory(outbuf, out_size);
out = outbuf; out = outbuf;
in = data; in = str;
in_end = data + (*size); in_end = str + (*size);
while (in < in_end) while (in < in_end)
{ {
c = *in++; c = *in++;
if (c == '\n') if (c == '\n')
{ {
*out++ = '\r'; *out++ = '\r';
@ -130,16 +130,17 @@ static BYTE* lf2crlf(BYTE* data, int* size)
return outbuf; return outbuf;
} }
static void crlf2lf(BYTE* data, int* size) static int ConvertLineEndingToLF(BYTE* str, int length)
{ {
BYTE c; BYTE c;
BYTE* out; BYTE* out;
BYTE* in; BYTE* in;
BYTE* in_end; BYTE* in_end;
int status = -1;
out = data; out = str;
in = data; in = str;
in_end = data + (*size); in_end = &str[length];
while (in < in_end) while (in < in_end)
{ {
@ -149,21 +150,19 @@ static void crlf2lf(BYTE* data, int* size)
*out++ = c; *out++ = c;
} }
*size = out - data; status = out - str;
return status;
} }
static void be2le(BYTE* data, int size) static void ByteSwapUnicode(WCHAR* wstr, int length)
{ {
BYTE c; WCHAR* end = &wstr[length];
while (size >= 2) while (wstr < end)
{ {
c = data[0]; *wstr = _byteswap_ushort(*wstr);
data[0] = data[1]; wstr++;
data[1] = c;
data += 2;
size -= 2;
} }
} }
@ -242,31 +241,6 @@ static xfCliprdrFormat* xf_cliprdr_get_format_by_atom(xfClipboard* clipboard, At
return NULL; return NULL;
} }
static void xf_cliprdr_send_supported_format_list(xfClipboard* clipboard)
{
int i;
CLIPRDR_FORMAT* formats;
CLIPRDR_FORMAT_LIST formatList;
ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST));
formatList.msgFlags = CB_RESPONSE_OK;
formatList.cFormats = clipboard->numClientFormats;
formats = (CLIPRDR_FORMAT*) calloc(formatList.cFormats, sizeof(CLIPRDR_FORMAT));
formatList.formats = formats;
for (i = 0; i < clipboard->numClientFormats; i++)
{
formats->formatId = clipboard->clientFormats[i].formatId;
formats->formatName = clipboard->clientFormats[i].formatName;
}
clipboard->context->ClientFormatList(clipboard->context, &formatList);
free(formats);
}
static void xf_cliprdr_send_data_request(xfClipboard* clipboard, UINT32 formatId) static void xf_cliprdr_send_data_request(xfClipboard* clipboard, UINT32 formatId)
{ {
CLIPRDR_FORMAT_DATA_REQUEST request; CLIPRDR_FORMAT_DATA_REQUEST request;
@ -305,6 +279,9 @@ static void xf_cliprdr_get_requested_targets(xfClipboard* clipboard)
CLIPRDR_FORMAT* formats = NULL; CLIPRDR_FORMAT* formats = NULL;
xfContext* xfc = clipboard->xfc; xfContext* xfc = clipboard->xfc;
if (!clipboard->numServerFormats)
return; /* server format list was not yet received */
XGetWindowProperty(xfc->display, xfc->drawable, clipboard->property_atom, XGetWindowProperty(xfc->display, xfc->drawable, clipboard->property_atom,
0, 200, 0, XA_ATOM, &atom, &format_property, &length, &bytes_left, &data); 0, 200, 0, XA_ATOM, &atom, &format_property, &length, &bytes_left, &data);
@ -350,7 +327,7 @@ static BYTE* xf_cliprdr_process_requested_unicodetext(BYTE* data, int* size)
WCHAR* outbuf = NULL; WCHAR* outbuf = NULL;
int out_size; int out_size;
inbuf = (char*) lf2crlf(data, size); inbuf = (char*) ConvertLineEndingToCRLF(data, size);
out_size = ConvertToUnicode(CP_UTF8, 0, inbuf, -1, &outbuf, 0); out_size = ConvertToUnicode(CP_UTF8, 0, inbuf, -1, &outbuf, 0);
free(inbuf); free(inbuf);
@ -363,7 +340,7 @@ static BYTE* xf_cliprdr_process_requested_text(BYTE* data, int* size)
{ {
BYTE* outbuf; BYTE* outbuf;
outbuf = lf2crlf(data, size); outbuf = ConvertLineEndingToCRLF(data, size);
return outbuf; return outbuf;
} }
@ -395,19 +372,23 @@ static BYTE* xf_cliprdr_process_requested_html(BYTE* data, int* size)
if (*size > 2) if (*size > 2)
{ {
if ((BYTE) data[0] == 0xFE && (BYTE) data[1] == 0xFF) BYTE bom[2];
CopyMemory(bom, data, 2);
if ((bom[0] == 0xFE) && (bom[1] == 0xFF))
{ {
be2le(data, *size); ByteSwapUnicode((WCHAR*) data, *size / 2);
} }
if ((BYTE) data[0] == 0xFF && (BYTE) data[1] == 0xFE) if ((bom[0] == 0xFF) && (bom[1] == 0xFE))
{ {
ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) (data + 2), ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) (data + 2),
(*size - 2) / 2, &inbuf, 0, NULL, NULL); (*size - 2) / 2, &inbuf, 0, NULL, NULL);
} }
} }
if (inbuf == NULL) if (!inbuf)
{ {
inbuf = calloc(1, *size + 1); inbuf = calloc(1, *size + 1);
CopyMemory(inbuf, data, *size); CopyMemory(inbuf, data, *size);
@ -424,17 +405,16 @@ static BYTE* xf_cliprdr_process_requested_html(BYTE* data, int* size)
in = (BYTE*) strstr((char*) inbuf, "<body"); in = (BYTE*) strstr((char*) inbuf, "<body");
if (in == NULL) if (!in)
{
in = (BYTE*) strstr((char*) inbuf, "<BODY"); in = (BYTE*) strstr((char*) inbuf, "<BODY");
}
/* StartHTML */ /* StartHTML */
snprintf(num, sizeof(num), "%010lu", (unsigned long) strlen((char*) outbuf)); snprintf(num, sizeof(num), "%010lu", (unsigned long) strlen((char*) outbuf));
CopyMemory(outbuf + 23, num, 10); CopyMemory(outbuf + 23, num, 10);
if (in == NULL)
{ if (!in)
strcat((char*) outbuf, "<HTML><BODY>"); strcat((char*) outbuf, "<HTML><BODY>");
}
strcat((char*) outbuf, "<!--StartFragment-->"); strcat((char*) outbuf, "<!--StartFragment-->");
/* StartFragment */ /* StartFragment */
snprintf(num, sizeof(num), "%010lu", (unsigned long) strlen((char*) outbuf)); snprintf(num, sizeof(num), "%010lu", (unsigned long) strlen((char*) outbuf));
@ -444,10 +424,10 @@ static BYTE* xf_cliprdr_process_requested_html(BYTE* data, int* size)
snprintf(num, sizeof(num), "%010lu", (unsigned long) strlen((char*) outbuf)); snprintf(num, sizeof(num), "%010lu", (unsigned long) strlen((char*) outbuf));
CopyMemory(outbuf + 93, num, 10); CopyMemory(outbuf + 93, num, 10);
strcat((char*) outbuf, "<!--EndFragment-->"); strcat((char*) outbuf, "<!--EndFragment-->");
if (in == NULL)
{ if (!in)
strcat((char*) outbuf, "</BODY></HTML>"); strcat((char*) outbuf, "</BODY></HTML>");
}
/* EndHTML */ /* EndHTML */
snprintf(num, sizeof(num), "%010lu", (unsigned long) strlen((char*) outbuf)); snprintf(num, sizeof(num), "%010lu", (unsigned long) strlen((char*) outbuf));
CopyMemory(outbuf + 43, num, 10); CopyMemory(outbuf + 43, num, 10);
@ -645,81 +625,109 @@ static void xf_cliprdr_provide_data(xfClipboard* clipboard, XEvent* respond)
} }
} }
static void xf_cliprdr_process_text(xfClipboard* clipboard, BYTE* data, int size) static int xf_cliprdr_process_text(BYTE* pSrcData, int SrcSize, BYTE** ppDstData)
{ {
clipboard->data = (BYTE*) malloc(size); int DstSize = -1;
CopyMemory(clipboard->data, data, size); BYTE* pDstData = NULL;
clipboard->data_length = size;
crlf2lf(clipboard->data, &clipboard->data_length); pDstData = (BYTE*) malloc(SrcSize);
CopyMemory(pDstData, pSrcData, SrcSize);
DstSize = SrcSize;
DstSize = ConvertLineEndingToLF(pDstData, DstSize);
*ppDstData = pDstData;
return DstSize;
} }
static void xf_cliprdr_process_unicodetext(xfClipboard* clipboard, BYTE* data, int size) static int xf_cliprdr_process_unicodetext(BYTE* pSrcData, int SrcSize, BYTE** ppDstData)
{ {
clipboard->data_length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) data, size / 2, (CHAR**) &(clipboard->data), 0, NULL, NULL); int DstSize = -1;
crlf2lf(clipboard->data, &clipboard->data_length); BYTE* pDstData = NULL;
DstSize = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) pSrcData,
SrcSize / 2, (CHAR**) &pDstData, 0, NULL, NULL);
DstSize = ConvertLineEndingToLF(pDstData, DstSize);
*ppDstData = pDstData;
return DstSize;
} }
static BOOL xf_cliprdr_process_dib(xfClipboard* clipboard, BYTE* data, int size) static int xf_cliprdr_process_dib(BYTE* pSrcData, int SrcSize, BYTE** ppDstData)
{ {
wStream* s; wStream* s;
UINT16 bpp; UINT16 bpp;
UINT32 offset; UINT32 offset;
UINT32 ncolors; UINT32 ncolors;
int DstSize = -1;
BYTE* pDstData = NULL;
/* size should be at least sizeof(BITMAPINFOHEADER) */ /* size should be at least sizeof(BITMAPINFOHEADER) */
if (size < 40) if (SrcSize < 40)
return FALSE; return -1;
s = Stream_New(data, size); s = Stream_New(pSrcData, SrcSize);
Stream_Seek(s, 14); Stream_Seek(s, 14);
Stream_Read_UINT16(s, bpp); Stream_Read_UINT16(s, bpp);
if ((bpp < 1) || (bpp > 32)) if ((bpp < 1) || (bpp > 32))
return FALSE; return -1;
Stream_Read_UINT32(s, ncolors); Stream_Read_UINT32(s, ncolors);
offset = 14 + 40 + (bpp <= 8 ? (ncolors == 0 ? (1 << bpp) : ncolors) * 4 : 0); offset = 14 + 40 + (bpp <= 8 ? (ncolors == 0 ? (1 << bpp) : ncolors) * 4 : 0);
Stream_Free(s, FALSE); Stream_Free(s, FALSE);
s = Stream_New(NULL, 14 + size); s = Stream_New(NULL, 14 + SrcSize);
Stream_Write_UINT8(s, 'B'); Stream_Write_UINT8(s, 'B');
Stream_Write_UINT8(s, 'M'); Stream_Write_UINT8(s, 'M');
Stream_Write_UINT32(s, 14 + size); Stream_Write_UINT32(s, 14 + SrcSize);
Stream_Write_UINT32(s, 0); Stream_Write_UINT32(s, 0);
Stream_Write_UINT32(s, offset); Stream_Write_UINT32(s, offset);
Stream_Write(s, data, size); Stream_Write(s, pSrcData, SrcSize);
clipboard->data = Stream_Buffer(s); pDstData = Stream_Buffer(s);
clipboard->data_length = Stream_GetPosition(s); DstSize = Stream_GetPosition(s);
Stream_Free(s, FALSE); Stream_Free(s, FALSE);
return TRUE; *ppDstData = pDstData;
return DstSize;
} }
static void xf_cliprdr_process_html(xfClipboard* clipboard, BYTE* data, int size) static int xf_cliprdr_process_html(BYTE* pSrcData, int SrcSize, BYTE** ppDstData)
{ {
int start; int start;
int end; int end;
char* start_str; char* start_str;
char* end_str; char* end_str;
int DstSize = -1;
BYTE* pDstData = NULL;
start_str = strstr((char*) data, "StartHTML:"); start_str = strstr((char*) pSrcData, "StartHTML:");
end_str = strstr((char*) data, "EndHTML:"); end_str = strstr((char*) pSrcData, "EndHTML:");
if (!start_str || !end_str) if (!start_str || !end_str)
return; return -1;
start = atoi(start_str + 10); start = atoi(start_str + 10);
end = atoi(end_str + 8); end = atoi(end_str + 8);
if ((start > size) || (end > size) || (start >= end)) if ((start > SrcSize) || (end > SrcSize) || (start >= end))
return; return -1;
clipboard->data = (BYTE*) malloc(size - start + 1); DstSize = end - start;
CopyMemory(clipboard->data, data + start, end - start);
clipboard->data_length = end - start; pDstData = (BYTE*) malloc(SrcSize - start + 1);
crlf2lf(clipboard->data, &clipboard->data_length); CopyMemory(pDstData, pSrcData + start, DstSize);
DstSize = ConvertLineEndingToLF(pDstData, DstSize);
*ppDstData = pDstData;
return DstSize;
} }
static BOOL xf_cliprdr_process_selection_notify(xfClipboard* clipboard, XEvent* xevent) static BOOL xf_cliprdr_process_selection_notify(xfClipboard* clipboard, XEvent* xevent)
@ -728,7 +736,7 @@ static BOOL xf_cliprdr_process_selection_notify(xfClipboard* clipboard, XEvent*
{ {
if (xevent->xselection.property == None) if (xevent->xselection.property == None)
{ {
xf_cliprdr_send_supported_format_list(clipboard); xf_cliprdr_send_client_format_list(clipboard);
} }
else else
{ {
@ -987,59 +995,31 @@ int xf_cliprdr_send_client_capabilities(xfClipboard* clipboard)
int xf_cliprdr_send_client_format_list(xfClipboard* clipboard) int xf_cliprdr_send_client_format_list(xfClipboard* clipboard)
{ {
UINT32 i, numFormats;
CLIPRDR_FORMAT* formats;
CLIPRDR_FORMAT_LIST formatList; CLIPRDR_FORMAT_LIST formatList;
xfContext* xfc = clipboard->xfc; xfContext* xfc = clipboard->xfc;
ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST));
if (!clipboard->sync) numFormats = clipboard->numClientFormats;
formats = (CLIPRDR_FORMAT*) calloc(numFormats, sizeof(CLIPRDR_FORMAT));
for (i = 0; i < numFormats; i++)
{ {
UINT32 i, numFormats; formats[i].formatId = clipboard->clientFormats[i].formatId;
CLIPRDR_FORMAT* formats; formats[i].formatName = clipboard->clientFormats[i].formatName;
numFormats = clipboard->numClientFormats;
formats = (CLIPRDR_FORMAT*) calloc(numFormats, sizeof(CLIPRDR_FORMAT));
for (i = 0; i < numFormats; i++)
{
formats[i].formatId = clipboard->clientFormats[i].formatId;
formats[i].formatName = clipboard->clientFormats[i].formatName;
}
formatList.msgFlags = CB_RESPONSE_OK;
formatList.cFormats = numFormats;
formatList.formats = formats;
clipboard->context->ClientFormatList(clipboard->context, &formatList);
free(formats);
return 1;
} }
if (xf_cliprdr_is_self_owned(clipboard)) formatList.msgFlags = CB_RESPONSE_OK;
{ formatList.cFormats = numFormats;
/** formatList.formats = formats;
* TODO: handle (raw?) format data
* The original code appears to be sending back the original,
* unmodified server format list here.
*/
formatList.msgFlags = CB_RESPONSE_OK; clipboard->context->ClientFormatList(clipboard->context, &formatList);
formatList.cFormats = clipboard->numServerFormats;
formatList.formats = clipboard->serverFormats;
clipboard->context->ClientFormatList(clipboard->context, &formatList); free(formats);
}
else if (clipboard->owner == None)
{
formatList.msgFlags = CB_RESPONSE_OK;
formatList.cFormats = 0;
formatList.formats = NULL;
clipboard->context->ClientFormatList(clipboard->context, &formatList); if (clipboard->owner != xfc->drawable)
}
else if (clipboard->owner != xfc->drawable)
{ {
/* Request the owner for TARGETS, and wait for SelectionNotify event */ /* Request the owner for TARGETS, and wait for SelectionNotify event */
XConvertSelection(xfc->display, clipboard->clipboard_atom, XConvertSelection(xfc->display, clipboard->clipboard_atom,
@ -1115,6 +1095,8 @@ static int xf_cliprdr_server_format_list(CliprdrClientContext* context, CLIPRDR_
free(clipboard->serverFormats); free(clipboard->serverFormats);
clipboard->serverFormats = NULL; clipboard->serverFormats = NULL;
clipboard->numServerFormats = 0;
} }
clipboard->numServerFormats = formatList->cFormats; clipboard->numServerFormats = formatList->cFormats;
@ -1200,6 +1182,8 @@ static int xf_cliprdr_server_format_data_request(CliprdrClientContext* context,
static int xf_cliprdr_server_format_data_response(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) static int xf_cliprdr_server_format_data_response(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
{ {
int status;
BYTE* pDstData;
UINT32 size = formatDataResponse->dataLen; UINT32 size = formatDataResponse->dataLen;
BYTE* data = formatDataResponse->requestedFormatData; BYTE* data = formatDataResponse->requestedFormatData;
xfClipboard* clipboard = (xfClipboard*) context->custom; xfClipboard* clipboard = (xfClipboard*) context->custom;
@ -1220,12 +1204,16 @@ static int xf_cliprdr_server_format_data_response(CliprdrClientContext* context,
clipboard->data = NULL; clipboard->data = NULL;
} }
status = -1;
pDstData = NULL;
switch (clipboard->data_format) switch (clipboard->data_format)
{ {
case CLIPRDR_FORMAT_RAW: case CLIPRDR_FORMAT_RAW:
case CB_FORMAT_PNG: case CB_FORMAT_PNG:
case CB_FORMAT_JPEG: case CB_FORMAT_JPEG:
case CB_FORMAT_GIF: case CB_FORMAT_GIF:
status = size;
clipboard->data = data; clipboard->data = data;
clipboard->data_length = size; clipboard->data_length = size;
data = NULL; data = NULL;
@ -1233,19 +1221,19 @@ static int xf_cliprdr_server_format_data_response(CliprdrClientContext* context,
break; break;
case CLIPRDR_FORMAT_TEXT: case CLIPRDR_FORMAT_TEXT:
xf_cliprdr_process_text(clipboard, data, size); status = xf_cliprdr_process_text(data, size, &pDstData);
break; break;
case CLIPRDR_FORMAT_UNICODETEXT: case CLIPRDR_FORMAT_UNICODETEXT:
xf_cliprdr_process_unicodetext(clipboard, data, size); status = xf_cliprdr_process_unicodetext(data, size, &pDstData);
break; break;
case CLIPRDR_FORMAT_DIB: case CLIPRDR_FORMAT_DIB:
xf_cliprdr_process_dib(clipboard, data, size); status = xf_cliprdr_process_dib(data, size, &pDstData);
break; break;
case CB_FORMAT_HTML: case CB_FORMAT_HTML:
xf_cliprdr_process_html(clipboard, data, size); status = xf_cliprdr_process_html(data, size, &pDstData);
break; break;
default: default:
@ -1253,6 +1241,17 @@ static int xf_cliprdr_server_format_data_response(CliprdrClientContext* context,
break; break;
} }
if (status < 1)
{
clipboard->data = NULL;
clipboard->data_length = 0;
}
else
{
clipboard->data = pDstData;
clipboard->data_length = status;
}
xf_cliprdr_provide_data(clipboard, clipboard->respond); xf_cliprdr_provide_data(clipboard, clipboard->respond);
} }