/** * Read guest's clipboard buffer and forward its content to host. * * @param u32ClientId Host clipboard connection. * @param pPasteboard Guest PasteBoard reference. * @param fFormats List of data formats (bit field) received from host. * * @returns IPRT status code. */ int vbclClipboardForwardToHost(uint32_t u32ClientId, PasteboardRef pPasteboard, uint32_t fFormats) { int rc = VINF_SUCCESS; void *pvData = NULL; uint32_t cbData = 0; uint32_t cbAlloc = 0; VBoxClientVerbose(3, "vbclClipboardForwardToHost: %d\n", fFormats); /* Walk across all item(s) formats */ uint32_t fFormatsLeft = fFormats; while (fFormatsLeft) { if (fFormatsLeft & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { VBoxClientVerbose(3, "requested VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT: %d\n", fFormats); RTUTF16 *pUtf16Str = NULL; /* First, try to get UTF16 encoded buffer */ rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeUTF16PlainText, &pvData, &cbData, &cbAlloc); if (RT_SUCCESS(rc)) { rc = RTUtf16DupEx(&pUtf16Str, (PRTUTF16)pvData, 0); if (RT_FAILURE(rc)) pUtf16Str = NULL; } else /* Failed to get UTF16 buffer */ { /* Then, try to get UTF8 encoded buffer */ rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeUTF8PlainText, &pvData, &cbData, &cbAlloc); if (RT_SUCCESS(rc)) { rc = RTStrToUtf16((const char *)pvData, &pUtf16Str); if (RT_FAILURE(rc)) pUtf16Str = NULL; } } /* Finally, we got UTF16 encoded buffer */ if (RT_SUCCESS(rc)) { rc = vbclClipboardHostPasteText(u32ClientId, (PRTUTF16)pvData, cbData); if (pUtf16Str) { RTUtf16Free(pUtf16Str); pUtf16Str = NULL; } vbclClipboardReleaseGuestData(&pvData, cbAlloc); } else { /* No data found or error occurred: send empty buffer */ rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, NULL, 0); } fFormatsLeft &= ~(uint32_t)VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT; } else if (fFormatsLeft & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) { VBoxClientVerbose(3, "requested VBOX_SHARED_CLIPBOARD_FMT_BITMAP: %d\n", fFormats); rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeBMP, &pvData, &cbData, &cbAlloc); if (RT_SUCCESS(rc)) { rc = vbclClipboardHostPasteBitmap(u32ClientId, pvData, cbData); vbclClipboardReleaseGuestData(&pvData, cbAlloc); } else { /* No data found or error occurred: send empty buffer */ rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHARED_CLIPBOARD_FMT_BITMAP, NULL, 0); } fFormatsLeft &= ~(uint32_t)VBOX_SHARED_CLIPBOARD_FMT_BITMAP; } else if (fFormatsLeft & VBOX_SHARED_CLIPBOARD_FMT_HTML) { VBoxClientVerbose(3, "requested VBOX_SHARED_CLIPBOARD_FMT_HTML: %d\n", fFormats); rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeHTML, &pvData, &cbData, &cbAlloc); if (RT_SUCCESS(rc)) { rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHARED_CLIPBOARD_FMT_HTML, pvData, cbData); vbclClipboardReleaseGuestData(&pvData, cbAlloc); } else { /* No data found or error occurred: send empty buffer */ rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHARED_CLIPBOARD_FMT_HTML, NULL, 0); } fFormatsLeft &= ~(uint32_t)VBOX_SHARED_CLIPBOARD_FMT_HTML; } else { VBoxClientVerbose(3, "requested data in unsupported format: %#x\n", fFormatsLeft); break; } } return rc; /** @todo r=bird: If there are multiple formats available, which rc is returned here? Does it matter? */ }
/** * Read content from the host clipboard and write it to the internal clipboard * structure for further processing. * * @param pPasteboardRef Reference to the global pasteboard. * @param fFormats The format type which should be read. * @param pv The destination buffer. * @param cb The size of the destination buffer. * @param pcbActual The size which is needed to transfer the content. * * @returns IPRT status code. */ int readFromPasteboard(PasteboardRef pPasteboard, uint32_t fFormat, void *pv, uint32_t cb, uint32_t *pcbActual) { Log(("readFromPasteboard: fFormat = %02X\n", fFormat)); OSStatus err = noErr; /* Make sure all is in sync */ PasteboardSynchronize(pPasteboard); /* Are some items in the pasteboard? */ ItemCount itemCount; err = PasteboardGetItemCount(pPasteboard, &itemCount); if (itemCount < 1) return VINF_SUCCESS; /* The id of the first element in the pasteboard */ int rc = VERR_NOT_SUPPORTED; PasteboardItemID itemID; if (!(err = PasteboardGetItemIdentifier(pPasteboard, 1, &itemID))) { /* The guest request unicode */ if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { CFDataRef outData; PRTUTF16 pwszTmp = NULL; /* Try utf-16 first */ if (!(err = PasteboardCopyItemFlavorData(pPasteboard, itemID, kUTTypeUTF16PlainText, &outData))) { Log(("Clipboard content is utf-16\n")); PRTUTF16 pwszString = (PRTUTF16)CFDataGetBytePtr(outData); if (pwszString) rc = RTUtf16DupEx(&pwszTmp, pwszString, 0); else rc = VERR_INVALID_PARAMETER; } /* Second try is utf-8 */ else if (!(err = PasteboardCopyItemFlavorData(pPasteboard, itemID, kUTTypeUTF8PlainText, &outData))) { Log(("readFromPasteboard: clipboard content is utf-8\n")); const char *pszString = (const char *)CFDataGetBytePtr(outData); if (pszString) rc = RTStrToUtf16(pszString, &pwszTmp); else rc = VERR_INVALID_PARAMETER; } if (pwszTmp) { /* Check how much longer will the converted text will be. */ size_t cwSrc = RTUtf16Len(pwszTmp); size_t cwDest; rc = vboxClipboardUtf16GetWinSize(pwszTmp, cwSrc, &cwDest); if (RT_FAILURE(rc)) { RTUtf16Free(pwszTmp); Log(("readFromPasteboard: clipboard conversion failed. vboxClipboardUtf16GetWinSize returned %Rrc. Abandoning.\n", rc)); AssertRCReturn(rc, rc); } /* Set the actually needed data size */ *pcbActual = cwDest * 2; /* Return success state */ rc = VINF_SUCCESS; /* Do not copy data if the dst buffer is not big enough. */ if (*pcbActual <= cb) { rc = vboxClipboardUtf16LinToWin(pwszTmp, RTUtf16Len(pwszTmp), static_cast <PRTUTF16>(pv), cb / 2); if (RT_FAILURE(rc)) { RTUtf16Free(pwszTmp); Log(("readFromPasteboard: clipboard conversion failed. vboxClipboardUtf16LinToWin() returned %Rrc. Abandoning.\n", rc)); AssertRCReturn(rc, rc); } #ifdef SHOW_CLIPBOARD_CONTENT Log(("readFromPasteboard: clipboard content: %ls\n", static_cast <PRTUTF16>(pv))); #endif } /* Free the temp string */ RTUtf16Free(pwszTmp); } } /* The guest request BITMAP */ else if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) { CFDataRef outData; const void *pTmp = NULL; size_t cbTmpSize; /* Get the data from the pasteboard */ if (!(err = PasteboardCopyItemFlavorData(pPasteboard, itemID, kUTTypeBMP, &outData))) { Log(("Clipboard content is BMP\n")); pTmp = CFDataGetBytePtr(outData); cbTmpSize = CFDataGetLength(outData); } if (pTmp) { const void *pDib; size_t cbDibSize; rc = vboxClipboardBmpGetDib(pTmp, cbTmpSize, &pDib, &cbDibSize); if (RT_FAILURE(rc)) { rc = VERR_NOT_SUPPORTED; Log(("readFromPasteboard: unknown bitmap format. vboxClipboardBmpGetDib returned %Rrc. Abandoning.\n", rc)); AssertRCReturn(rc, rc); } *pcbActual = cbDibSize; /* Return success state */ rc = VINF_SUCCESS; /* Do not copy data if the dst buffer is not big enough. */ if (*pcbActual <= cb) { memcpy(pv, pDib, cbDibSize); #ifdef SHOW_CLIPBOARD_CONTENT Log(("readFromPasteboard: clipboard content bitmap %d bytes\n", cbDibSize)); #endif } } } } Log(("readFromPasteboard: rc = %02X\n", rc)); return rc; }