static void* clipboard_synthesize_cf_unicodetext(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) { int size; int status; char* crlfStr = NULL; WCHAR* pDstData = NULL; if ((formatId == CF_TEXT) || (formatId == CF_OEMTEXT) || (formatId == ClipboardGetFormatId(clipboard, "UTF8_STRING")) || (formatId == ClipboardGetFormatId(clipboard, "text/plain")) || (formatId == ClipboardGetFormatId(clipboard, "TEXT")) || (formatId == ClipboardGetFormatId(clipboard, "STRING"))) { if (!pSize || (*pSize > INT32_MAX)) return NULL; size = (int) * pSize; crlfStr = ConvertLineEndingToCRLF((char*) data, &size); if (!crlfStr) return NULL; status = ConvertToUnicode(CP_UTF8, 0, crlfStr, size, &pDstData, 0); free(crlfStr); if (status <= 0) return NULL; *pSize = status * 2; } return (void*) pDstData; }
static void* clipboard_synthesize_cf_text(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) { int size; char* pDstData = NULL; if (formatId == CF_UNICODETEXT) { size_t wsize; char* str = NULL; if (*pSize > INT32_MAX) return NULL; wsize = _wcsnlen(data, (*pSize) / 2); size = ConvertFromUnicode(CP_UTF8, 0, (LPCWSTR) data, wsize, (CHAR**) &str, 0, NULL, NULL); if (!str) return NULL; pDstData = ConvertLineEndingToCRLF((const char*) str, &size); free(str); *pSize = size; return pDstData; } else if ((formatId == CF_TEXT) || (formatId == CF_OEMTEXT) || (formatId == ClipboardGetFormatId(clipboard, "UTF8_STRING")) || (formatId == ClipboardGetFormatId(clipboard, "text/plain")) || (formatId == ClipboardGetFormatId(clipboard, "TEXT")) || (formatId == ClipboardGetFormatId(clipboard, "STRING"))) { size = (INT64) * pSize; pDstData = ConvertLineEndingToCRLF((const char*) data, &size); if (!pDstData) return NULL; *pSize = size; return pDstData; } return NULL; }
static void* clipboard_synthesize_cf_dibv5(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) { if (formatId == CF_DIB) { } else if (formatId == ClipboardGetFormatId(clipboard, "image/bmp")) { } return NULL; }
static void* clipboard_synthesize_utf8_string(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) { INT64 size; char* pDstData = NULL; if (formatId == CF_UNICODETEXT) { size_t wsize = _wcsnlen(data, (*pSize) / 2); size = ConvertFromUnicode(CP_UTF8, 0, (LPWSTR) data, wsize, (CHAR**) &pDstData, 0, NULL, NULL); if (!pDstData) return NULL; size = ConvertLineEndingToLF(pDstData, size); *pSize = size; return pDstData; } else if ((formatId == CF_TEXT) || (formatId == CF_OEMTEXT) || (formatId == ClipboardGetFormatId(clipboard, "text/plain")) || (formatId == ClipboardGetFormatId(clipboard, "TEXT")) || (formatId == ClipboardGetFormatId(clipboard, "STRING"))) { size = (INT64) * pSize; pDstData = (char*) malloc(size); if (!pDstData) return NULL; CopyMemory(pDstData, data, size); size = ConvertLineEndingToLF((char*) pDstData, size); *pSize = size; return pDstData; } return NULL; }
static void* clipboard_synthesize_text_html(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) { long beg; long end; char* str; char* begStr; char* endStr; INT64 SrcSize; long DstSize = -1; BYTE* pDstData = NULL; if (formatId == ClipboardGetFormatId(clipboard, "HTML Format")) { str = (char*) data; SrcSize = (INT64) * pSize; begStr = strstr(str, "StartHTML:"); endStr = strstr(str, "EndHTML:"); if (!begStr || !endStr) return NULL; errno = 0; beg = strtol(&begStr[10], NULL, 10); if (errno != 0) return NULL; end = strtol(&endStr[8], NULL, 10); if (beg < 0 || end < 0 || (beg > SrcSize) || (end > SrcSize) || (beg >= end) || (errno != 0)) return NULL; DstSize = end - beg; pDstData = (BYTE*) malloc(SrcSize - beg + 1); if (!pDstData) return NULL; CopyMemory(pDstData, &str[beg], DstSize); DstSize = ConvertLineEndingToLF((char*) pDstData, DstSize); *pSize = (UINT32) DstSize; } return (void*) pDstData; }
static void* clipboard_synthesize_cf_dib(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) { UINT32 SrcSize; UINT32 DstSize; BYTE* pDstData; SrcSize = *pSize; if (formatId == CF_DIBV5) { } else if (formatId == ClipboardGetFormatId(clipboard, "image/bmp")) { BITMAPFILEHEADER* pFileHeader; if (SrcSize < (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER))) return NULL; pFileHeader = (BITMAPFILEHEADER*) data; if (pFileHeader->bfType != 0x4D42) return NULL; DstSize = SrcSize - sizeof(BITMAPFILEHEADER); pDstData = (BYTE*) malloc(DstSize); if (!pDstData) return NULL; data = (void*) & ((BYTE*) data)[sizeof(BITMAPFILEHEADER)]; CopyMemory(pDstData, data, DstSize); *pSize = DstSize; return pDstData; } return NULL; }
static void* clipboard_synthesize_html_format(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize) { char* pSrcData = NULL; char* pDstData = NULL; INT64 SrcSize = (INT64) * pSize; if (formatId == ClipboardGetFormatId(clipboard, "text/html")) { char* body; BYTE bom[2]; char num[20]; WCHAR* wstr; if (SrcSize > 2) { CopyMemory(bom, data, 2); if ((bom[0] == 0xFE) && (bom[1] == 0xFF)) { ByteSwapUnicode((WCHAR*) data, SrcSize / 2); } if ((bom[0] == 0xFF) && (bom[1] == 0xFE)) { wstr = (WCHAR*) & ((BYTE*) data)[2]; ConvertFromUnicode(CP_UTF8, 0, wstr, (SrcSize - 2) / 2, &pSrcData, 0, NULL, NULL); } } if (!pSrcData) { pSrcData = (char*) calloc(1, SrcSize + 1); if (!pSrcData) return NULL; CopyMemory(pSrcData, data, SrcSize); } pDstData = (char*) calloc(1, SrcSize + 200); if (!pDstData) { free(pSrcData); return NULL; } sprintf_s(pDstData, SrcSize + 200, "Version:0.9\r\n" "StartHTML:0000000000\r\n" "EndHTML:0000000000\r\n" "StartFragment:0000000000\r\n" "EndFragment:0000000000\r\n"); body = strstr(pSrcData, "<body"); if (!body) body = strstr(pSrcData, "<BODY"); /* StartHTML */ sprintf_s(num, sizeof(num), "%010"PRIuz"", strlen(pDstData)); CopyMemory(&pDstData[23], num, 10); if (!body) strcat(pDstData, "<HTML><BODY>"); strcat(pDstData, "<!--StartFragment-->"); /* StartFragment */ sprintf_s(num, sizeof(num), "%010"PRIuz"", strlen(pDstData)); CopyMemory(&pDstData[69], num, 10); strcat(pDstData, pSrcData); /* EndFragment */ sprintf_s(num, sizeof(num), "%010"PRIuz"", strlen(pDstData)); CopyMemory(&pDstData[93], num, 10); strcat(pDstData, "<!--EndFragment-->"); if (!body) strcat(pDstData, "</BODY></HTML>"); /* EndHTML */ sprintf_s(num, sizeof(num), "%010"PRIuz"", strlen(pDstData)); CopyMemory(&pDstData[43], num, 10); *pSize = (UINT32) strlen(pDstData) + 1; free(pSrcData); } return pDstData; }
static int xf_cliprdr_server_format_data_response(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) { BOOL bSuccess; BYTE* pSrcData; BYTE* pDstData; UINT32 DstSize; UINT32 SrcSize; UINT32 formatId; UINT32 altFormatId; xfCliprdrFormat* format; BOOL nullTerminated = FALSE; UINT32 size = formatDataResponse->dataLen; BYTE* data = formatDataResponse->requestedFormatData; xfClipboard* clipboard = (xfClipboard*) context->custom; xfContext* xfc = clipboard->xfc; if (!clipboard->respond) return 1; format = xf_cliprdr_get_format_by_id(clipboard, clipboard->requestedFormatId); if (clipboard->data) { free(clipboard->data); clipboard->data = NULL; } pDstData = NULL; DstSize = 0; formatId = 0; altFormatId = 0; switch (clipboard->data_format) { case CF_TEXT: formatId = CF_TEXT; altFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); nullTerminated = TRUE; break; case CF_OEMTEXT: formatId = CF_OEMTEXT; altFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); nullTerminated = TRUE; break; case CF_UNICODETEXT: formatId = CF_UNICODETEXT; altFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); nullTerminated = TRUE; break; case CF_DIB: formatId = CF_DIB; altFormatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); break; case CB_FORMAT_HTML: formatId = ClipboardGetFormatId(clipboard->system, "HTML Format"); altFormatId = ClipboardGetFormatId(clipboard->system, "text/html"); nullTerminated = TRUE; break; } SrcSize = (UINT32) size; pSrcData = (BYTE*) malloc(SrcSize); if (!pSrcData) return -1; CopyMemory(pSrcData, data, SrcSize); bSuccess = ClipboardSetData(clipboard->system, formatId, (void*) pSrcData, SrcSize); if (!bSuccess) free (pSrcData); if (bSuccess && altFormatId) { DstSize = 0; pDstData = (BYTE*) ClipboardGetData(clipboard->system, altFormatId, &DstSize); if ((DstSize > 1) && nullTerminated) DstSize--; } clipboard->data = pDstData; clipboard->data_length = DstSize; xf_cliprdr_provide_data(clipboard, clipboard->respond, pDstData, DstSize); XSendEvent(xfc->display, clipboard->respond->xselection.requestor, 0, 0, clipboard->respond); XFlush(xfc->display); free(clipboard->respond); clipboard->respond = NULL; return 1; }
static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasData, BYTE* data, int size) { BOOL bSuccess; UINT32 SrcSize; UINT32 DstSize; UINT32 formatId; UINT32 altFormatId; BYTE* pSrcData = NULL; BYTE* pDstData = NULL; xfCliprdrFormat* format; if (clipboard->incr_starts && hasData) return; format = xf_cliprdr_get_format_by_id(clipboard, clipboard->requestedFormatId); if (!hasData || !data || !format) { xf_cliprdr_send_data_response(clipboard, NULL, 0); return; } formatId = 0; altFormatId = 0; switch (format->formatId) { case CF_TEXT: case CF_OEMTEXT: case CF_UNICODETEXT: size = strlen((char*) data) + 1; formatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); break; case CF_DIB: formatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); break; case CB_FORMAT_HTML: size = strlen((char*) data) + 1; formatId = ClipboardGetFormatId(clipboard->system, "text/html"); break; } SrcSize = (UINT32) size; pSrcData = (BYTE*) malloc(SrcSize); if (!pSrcData) return; CopyMemory(pSrcData, data, SrcSize); bSuccess = ClipboardSetData(clipboard->system, formatId, (void*) pSrcData, SrcSize); if (!bSuccess) free(pSrcData); altFormatId = clipboard->requestedFormatId; if (bSuccess && altFormatId) { DstSize = 0; pDstData = (BYTE*) ClipboardGetData(clipboard->system, altFormatId, &DstSize); } if (!pDstData) { xf_cliprdr_send_data_response(clipboard, NULL, 0); return; } xf_cliprdr_send_data_response(clipboard, pDstData, (int) DstSize); free(pDstData); }
static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasData, BYTE* data, int size) { BOOL bSuccess; UINT32 SrcSize; UINT32 DstSize; UINT32 srcFormatId; UINT32 dstFormatId; BYTE* pDstData = NULL; xfCliprdrFormat* format; if (clipboard->incr_starts && hasData) return; format = xf_cliprdr_get_client_format_by_id(clipboard, clipboard->requestedFormatId); if (!hasData || !data || !format) { xf_cliprdr_send_data_response(clipboard, NULL, 0); return; } srcFormatId = 0; switch (format->formatId) { case CF_RAW: srcFormatId = CF_RAW; break; case CF_TEXT: case CF_OEMTEXT: case CF_UNICODETEXT: size = strlen((char*) data) + 1; srcFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); break; case CF_DIB: srcFormatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); break; case CB_FORMAT_HTML: srcFormatId = ClipboardGetFormatId(clipboard->system, "text/html"); break; case CB_FORMAT_TEXTURILIST: srcFormatId = ClipboardGetFormatId(clipboard->system, "text/uri-list"); break; } SrcSize = (UINT32) size; bSuccess = ClipboardSetData(clipboard->system, srcFormatId, data, SrcSize); if (format->formatName) dstFormatId = ClipboardGetFormatId(clipboard->system, format->formatName); else dstFormatId = format->formatId; if (bSuccess) { DstSize = 0; pDstData = (BYTE*) ClipboardGetData(clipboard->system, dstFormatId, &DstSize); } if (!pDstData) { xf_cliprdr_send_data_response(clipboard, NULL, 0); return; } /* * File lists require a bit of postprocessing to convert them from WinPR's FILDESCRIPTOR * format to CLIPRDR_FILELIST expected by the server. * * We check for "FileGroupDescriptorW" format being registered (i.e., nonzero) in order * to not process CF_RAW as a file list in case WinPR does not support file transfers. */ if (dstFormatId && (dstFormatId == ClipboardGetFormatId(clipboard->system, "FileGroupDescriptorW"))) { UINT error = NO_ERROR; FILEDESCRIPTOR* file_array = (FILEDESCRIPTOR*) pDstData; UINT32 file_count = DstSize / sizeof(FILEDESCRIPTOR); pDstData = NULL; DstSize = 0; error = cliprdr_serialize_file_list(file_array, file_count, &pDstData, &DstSize); if (error) WLog_ERR(TAG, "failed to serialize CLIPRDR_FILELIST: 0x%08X", error); free(file_array); } xf_cliprdr_send_data_response(clipboard, pDstData, (int) DstSize); free(pDstData); }
xfClipboard* xf_clipboard_new(xfContext* xfc) { int i, n = 0; rdpChannels* channels; xfClipboard* clipboard; if (!(clipboard = (xfClipboard*) calloc(1, sizeof(xfClipboard)))) { WLog_ERR(TAG, "failed to allocate xfClipboard data"); return NULL; } xfc->clipboard = clipboard; clipboard->xfc = xfc; channels = ((rdpContext*) xfc)->channels; clipboard->channels = channels; clipboard->system = ClipboardCreate(); clipboard->requestedFormatId = -1; clipboard->root_window = DefaultRootWindow(xfc->display); clipboard->clipboard_atom = XInternAtom(xfc->display, "CLIPBOARD", FALSE); if (clipboard->clipboard_atom == None) { WLog_ERR(TAG, "unable to get CLIPBOARD atom"); goto error; } clipboard->property_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR", FALSE); clipboard->raw_transfer_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR_RAW", FALSE); clipboard->raw_format_list_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR_FORMATS", FALSE); xf_cliprdr_set_raw_transfer_enabled(clipboard, TRUE); XSelectInput(xfc->display, clipboard->root_window, PropertyChangeMask); #ifdef WITH_XFIXES if (XFixesQueryExtension(xfc->display, &clipboard->xfixes_event_base, &clipboard->xfixes_error_base)) { int xfmajor, xfminor; if (XFixesQueryVersion(xfc->display, &xfmajor, &xfminor)) { XFixesSelectSelectionInput(xfc->display, clipboard->root_window, clipboard->clipboard_atom, XFixesSetSelectionOwnerNotifyMask); clipboard->xfixes_supported = TRUE; } else { WLog_ERR(TAG, "Error querying X Fixes extension version"); } } else { WLog_ERR(TAG, "Error loading X Fixes extension"); } #else WLog_ERR(TAG, "Warning: Using clipboard redirection without XFIXES extension is strongly discouraged!"); #endif clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "_FREERDP_RAW", False); clipboard->clientFormats[n].formatId = CF_RAW; n++; clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "UTF8_STRING", False); clipboard->clientFormats[n].formatId = CF_UNICODETEXT; n++; clipboard->clientFormats[n].atom = XA_STRING; clipboard->clientFormats[n].formatId = CF_TEXT; n++; clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/png", False); clipboard->clientFormats[n].formatId = CB_FORMAT_PNG; n++; clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/jpeg", False); clipboard->clientFormats[n].formatId = CB_FORMAT_JPEG; n++; clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/gif", False); clipboard->clientFormats[n].formatId = CB_FORMAT_GIF; n++; clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "image/bmp", False); clipboard->clientFormats[n].formatId = CF_DIB; n++; clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "text/html", False); clipboard->clientFormats[n].formatId = CB_FORMAT_HTML; clipboard->clientFormats[n].formatName = _strdup("HTML Format"); if (!clipboard->clientFormats[n].formatName) goto error; n++; /* * Existence of registered format IDs for file formats does not guarantee that they are * in fact supported by wClipboard (as further initialization may have failed after format * registration). However, they are definitely not supported if there are no registered * formats. In this case we should not list file formats in TARGETS. */ if (ClipboardGetFormatId(clipboard->system, "text/uri-list")) { clipboard->file_formats_registered = TRUE; clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "text/uri-list", False); clipboard->clientFormats[n].formatId = CB_FORMAT_TEXTURILIST; clipboard->clientFormats[n].formatName = _strdup("FileGroupDescriptorW"); if (!clipboard->clientFormats[n].formatName) goto error; n++; } clipboard->numClientFormats = n; clipboard->targets[0] = XInternAtom(xfc->display, "TIMESTAMP", FALSE); clipboard->targets[1] = XInternAtom(xfc->display, "TARGETS", FALSE); clipboard->numTargets = 2; clipboard->incr_atom = XInternAtom(xfc->display, "INCR", FALSE); clipboard->delegate = ClipboardGetDelegate(clipboard->system); clipboard->delegate->custom = clipboard; clipboard->delegate->ClipboardFileSizeSuccess = xf_cliprdr_clipboard_file_size_success; clipboard->delegate->ClipboardFileSizeFailure = xf_cliprdr_clipboard_file_size_failure; clipboard->delegate->ClipboardFileRangeSuccess = xf_cliprdr_clipboard_file_range_success; clipboard->delegate->ClipboardFileRangeFailure = xf_cliprdr_clipboard_file_range_failure; return clipboard; error: for (i = 0; i < n; i++) free(clipboard->clientFormats[i].formatName); ClipboardDestroy(clipboard->system); free(clipboard); return NULL; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) { BOOL bSuccess; BYTE* pDstData; UINT32 DstSize; UINT32 SrcSize; UINT32 srcFormatId; UINT32 dstFormatId; BOOL nullTerminated = FALSE; UINT32 size = formatDataResponse->dataLen; BYTE* data = formatDataResponse->requestedFormatData; xfClipboard* clipboard = (xfClipboard*) context->custom; xfContext* xfc = clipboard->xfc; if (!clipboard->respond) return CHANNEL_RC_OK; xf_cliprdr_clear_cached_data(clipboard); pDstData = NULL; DstSize = 0; srcFormatId = 0; dstFormatId = 0; if (clipboard->data_raw_format) { srcFormatId = CF_RAW; dstFormatId = CF_RAW; } else if (clipboard->data_format_name) { if (strcmp(clipboard->data_format_name, "HTML Format") == 0) { srcFormatId = ClipboardGetFormatId(clipboard->system, "HTML Format"); dstFormatId = ClipboardGetFormatId(clipboard->system, "text/html"); nullTerminated = TRUE; } } else { switch (clipboard->data_format_id) { case CF_TEXT: srcFormatId = CF_TEXT; dstFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); nullTerminated = TRUE; break; case CF_OEMTEXT: srcFormatId = CF_OEMTEXT; dstFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); nullTerminated = TRUE; break; case CF_UNICODETEXT: srcFormatId = CF_UNICODETEXT; dstFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); nullTerminated = TRUE; break; case CF_DIB: srcFormatId = CF_DIB; dstFormatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); break; } } SrcSize = (UINT32) size; bSuccess = ClipboardSetData(clipboard->system, srcFormatId, data, SrcSize); if (bSuccess) { DstSize = 0; pDstData = (BYTE*) ClipboardGetData(clipboard->system, dstFormatId, &DstSize); if (!pDstData) { WLog_ERR(TAG, "failed to get clipboard data in format %s [source format %s]", ClipboardGetFormatName(clipboard, dstFormatId), ClipboardGetFormatName(clipboard, srcFormatId)); return ERROR_INTERNAL_ERROR; } if (nullTerminated) { while (DstSize > 0 && pDstData[DstSize - 1] == '\0') DstSize--; } } /* Cache converted and original data to avoid doing a possibly costly * conversion again on subsequent requests */ clipboard->data = pDstData; clipboard->data_length = DstSize; /* We have to copy the original data again, as pSrcData is now owned * by clipboard->system. Memory allocation failure is not fatal here * as this is only a cached value. */ clipboard->data_raw = (BYTE*) malloc(size); if (clipboard->data_raw) { CopyMemory(clipboard->data_raw, data, size); clipboard->data_raw_length = size; } else { WLog_WARN(TAG, "failed to allocate %"PRIu32" bytes for a copy of raw clipboard data", size); } xf_cliprdr_provide_data(clipboard, clipboard->respond, pDstData, DstSize); XSendEvent(xfc->display, clipboard->respond->xselection.requestor, 0, 0, clipboard->respond); XFlush(xfc->display); free(clipboard->respond); clipboard->respond = NULL; return CHANNEL_RC_OK; }