VirtualBox

source: vbox/trunk/src/VBox/Additions/darwin/VBoxClient/VBoxClientClipboardGuestToHost.cpp@ 78188

Last change on this file since 78188 was 78188, checked in by vboxsync, 6 years ago

Shared Clipboard: Trying to fix the failing darwin builds

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.4 KB
Line 
1/** $Id: VBoxClientClipboardGuestToHost.cpp 78188 2019-04-17 22:35:51Z vboxsync $ */
2/** @file
3 * VBoxClient - Shared Clipboard Guest -> Host copying, Darwin.
4 */
5
6/*
7 * Copyright (C) 2007-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <Carbon/Carbon.h>
23#include <signal.h>
24#include <stdlib.h>
25
26#include <iprt/thread.h>
27#include <iprt/mem.h>
28#include <iprt/initterm.h>
29#include <iprt/message.h>
30#include <iprt/stream.h>
31#include <iprt/utf16.h>
32#include <VBox/VBoxGuestLib.h>
33#include <VBox/GuestHost/SharedClipboard.h>
34#include <VBox/HostServices/VBoxClipboardSvc.h>
35#include <VBox/GuestHost/clipboard-helper.h>
36#include "VBoxClientInternal.h"
37
38/**
39 * Walk through pasteboard items and report currently available item types.
40 *
41 * @param pPasteboard Reference to guest Pasteboard.
42 * @returns Available formats bit field.
43 */
44uint32_t vbclClipboardGetAvailableFormats(PasteboardRef pPasteboard)
45{
46 uint32_t fFormats = 0;
47 ItemCount cItems = 0;
48 ItemCount iItem;
49 OSStatus rc;
50
51#define VBOXCL_ADD_FORMAT_IF_PRESENT(a_kDarwinFmt, a_fVBoxFmt) \
52 if (PasteboardCopyItemFlavorData(pPasteboard, iItemID, a_kDarwinFmt, &flavorData) == noErr) \
53 { \
54 fFormats |= (uint32_t)a_fVBoxFmt; \
55 CFRelease(flavorData); \
56 }
57
58 rc = PasteboardGetItemCount(pPasteboard, &cItems);
59 AssertReturn((rc == noErr) && (cItems > 0), fFormats);
60
61 for (iItem = 1; iItem <= cItems; iItem++)
62 {
63 PasteboardItemID iItemID;
64 CFDataRef flavorData;
65
66 rc = PasteboardGetItemIdentifier(pPasteboard, iItem, &iItemID);
67 if (rc == noErr)
68 {
69 VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeUTF16PlainText, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
70 VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeUTF8PlainText, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
71 VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeBMP, VBOX_SHARED_CLIPBOARD_FMT_BITMAP );
72 VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeHTML, VBOX_SHARED_CLIPBOARD_FMT_HTML );
73
74#ifdef CLIPBOARD_DUMP_CONTENT_FORMATS
75 CFArrayRef flavorTypeArray;
76 CFIndex flavorCount;
77 CFStringRef flavorType;
78
79 rc = PasteboardCopyItemFlavors(pPasteboard, iItemID, &flavorTypeArray);
80 if (rc == noErr)
81 {
82 VBoxClientVerbose(3, "SCAN..\n");
83 flavorCount = CFArrayGetCount(flavorTypeArray);
84 VBoxClientVerbose(3, "SCAN (%d)..\n", (int)flavorCount);
85 for(CFIndex flavorIndex = 0; flavorIndex < flavorCount; flavorIndex++)
86 {
87 VBoxClientVerbose(3, "SCAN #%d..\n", (int)flavorIndex);
88 flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, flavorIndex);
89
90 CFDataRef flavorData1;
91 rc = PasteboardCopyItemFlavorData(pPasteboard, iItemID, flavorType, &flavorData1);
92 if (rc == noErr)
93 {
94 VBoxClientVerbose(3, "Found: %s, size: %d\n", (char *)CFStringGetCStringPtr(flavorType, kCFStringEncodingMacRoman), (int)CFDataGetLength(flavorData1));
95 CFRelease(flavorData1);
96 }
97 }
98 VBoxClientVerbose(3, "SCAN COMPLETE\n");
99 CFRelease(flavorTypeArray);
100 }
101#endif /* CLIPBOARD_DUMP_CONTENT_FORMATS */
102 }
103 }
104
105#undef VBOXCL_ADD_FORMAT_IF_PRESENT
106
107 return fFormats;
108}
109
110
111/**
112 * Search for content of specified type in guest clipboard buffer and put
113 * it into newly allocated buffer.
114 *
115 * @param pPasteboard Guest PasteBoard reference.
116 * @param fFormat Data formats we are looking for.
117 * @param ppvData Where to return pointer to the received data. M
118 * @param pcbData Where to return the size of the data.
119 * @param pcbAlloc Where to return the size of the memory block
120 * *ppvData pointes to. (Usually greater than *cbData
121 * because the allocation is page aligned.)
122 * @returns IPRT status code.
123 */
124static int vbclClipboardReadGuestData(PasteboardRef pPasteboard, CFStringRef sFormat, void **ppvData, uint32_t *pcbData,
125 uint32_t *pcbAlloc)
126{
127 ItemCount cItems, iItem;
128 OSStatus rc;
129
130 void *pvData = NULL;
131 uint32_t cbData = 0;
132 uint32_t cbAlloc = 0;
133
134 AssertPtrReturn(ppvData, VERR_INVALID_POINTER);
135 AssertPtrReturn(pcbData, VERR_INVALID_POINTER);
136 AssertPtrReturn(pcbAlloc, VERR_INVALID_POINTER);
137
138 rc = PasteboardGetItemCount(pPasteboard, &cItems);
139 AssertReturn(rc == noErr, VERR_INVALID_PARAMETER);
140 AssertReturn(cItems > 0, VERR_INVALID_PARAMETER);
141
142 /* Walk through all the items in PasteBoard in order to find
143 that one that correcponds to requested data format. */
144 for (iItem = 1; iItem <= cItems; iItem++)
145 {
146 PasteboardItemID iItemID;
147 CFDataRef flavorData;
148
149 /* Now, get the item's flavors that corresponds to requested type. */
150 rc = PasteboardGetItemIdentifier(pPasteboard, iItem, &iItemID);
151 AssertReturn(rc == noErr, VERR_INVALID_PARAMETER);
152 rc = PasteboardCopyItemFlavorData(pPasteboard, iItemID, sFormat, &flavorData);
153 if (rc == noErr)
154 {
155 void *flavorDataPtr = (void *)CFDataGetBytePtr(flavorData);
156 cbData = CFDataGetLength(flavorData);
157 if (flavorDataPtr && cbData > 0)
158 {
159 cbAlloc = RT_ALIGN_32(cbData, PAGE_SIZE);
160 pvData = RTMemPageAllocZ(cbAlloc);
161 if (pvData)
162 memcpy(pvData, flavorDataPtr, cbData);
163 }
164
165 CFRelease(flavorData);
166
167 /* Found first matching item, no more search. */
168 break;
169 }
170
171 }
172
173 /* Found match */
174 if (pvData)
175 {
176 *ppvData = pvData;
177 *pcbData = cbData;
178 *pcbAlloc = cbAlloc;
179
180 return VINF_SUCCESS;
181 }
182
183 return VERR_INVALID_PARAMETER;
184}
185
186
187/**
188 * Release resources occupied by vbclClipboardReadGuestData().
189 */
190static void vbclClipboardReleaseGuestData(void **ppvData, uint32_t cbAlloc)
191{
192 AssertReturnVoid(ppvData);
193 RTMemPageFree(*ppvData, cbAlloc);
194 *ppvData = NULL;
195}
196
197/**
198 * Pass data to host.
199 */
200static int vbclClipboardHostPasteData(uint32_t u32ClientId, uint32_t u32Format, const void *pvData, uint32_t cbData)
201{
202 /* Allow empty buffers */
203 if (cbData == 0)
204 return VbglR3ClipboardWriteData(u32ClientId, u32Format, NULL, 0);
205
206 AssertReturn(pvData, VERR_INVALID_PARAMETER);
207 return VbglR3ClipboardWriteData(u32ClientId, u32Format, (void *)pvData, cbData); /** @todo r=bird: Why on earth does a write function like VbglR3ClipboardWriteData take a non-const parameter? */
208}
209
210/**
211 * Paste text data into host clipboard.
212 *
213 * @param u32ClientId Host clipboard connection.
214 * @param pwszData UTF-16 encoded string.
215 * @param cbData The length of the string, in bytes, probably
216 * including a terminating zero.
217 */
218static int vbclClipboardHostPasteText(uint32_t u32ClientId, PRTUTF16 pwszData, uint32_t cbData)
219{
220 AssertReturn(cbData > 0, VERR_INVALID_PARAMETER);
221 AssertPtrReturn(pwszData, VERR_INVALID_POINTER);
222
223 size_t cwcActual; /* (includes a schwarzenegger character) */
224 int rc = vboxClipboardUtf16GetWinSize(pwszData, cbData / sizeof(RTUTF16), &cwcActual);
225 AssertReturn(RT_SUCCESS(rc), rc);
226
227 PRTUTF16 pwszWinTmp = (PRTUTF16)RTMemAlloc(cwcActual * sizeof(RTUTF16));
228 AssertReturn(pwszWinTmp, VERR_NO_MEMORY);
229
230 rc = vboxClipboardUtf16LinToWin(pwszData, cbData / sizeof(RTUTF16), pwszWinTmp, cwcActual);
231 if (RT_SUCCESS(rc))
232 rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
233 pwszWinTmp, cwcActual * sizeof(RTUTF16));
234
235 RTMemFree(pwszWinTmp);
236
237 return rc;
238}
239
240
241/**
242 * Paste a bitmap onto the host clipboard.
243 *
244 * @param u32ClientId Host clipboard connection.
245 * @param pvData The bitmap data.
246 * @param cbData The size of the bitmap.
247 */
248static int vbclClipboardHostPasteBitmap(uint32_t u32ClientId, void *pvData, uint32_t cbData)
249{
250 const void *pvDib;
251 size_t cbDib;
252 int rc = vboxClipboardBmpGetDib(pvData, cbData, &pvDib, &cbDib);
253 AssertRCReturn(rc, rc);
254
255 rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHARED_CLIPBOARD_FMT_BITMAP, pvDib, cbDib);
256
257 return rc;
258}
259
260
261/**
262 * Read guest's clipboard buffer and forward its content to host.
263 *
264 * @param u32ClientId Host clipboard connection.
265 * @param pPasteboard Guest PasteBoard reference.
266 * @param fFormats List of data formats (bit field) received from host.
267 *
268 * @returns IPRT status code.
269 */
270int vbclClipboardForwardToHost(uint32_t u32ClientId, PasteboardRef pPasteboard, uint32_t fFormats)
271{
272 int rc = VINF_SUCCESS;
273
274 void *pvData = NULL;
275 uint32_t cbData = 0;
276 uint32_t cbAlloc = 0;
277
278 VBoxClientVerbose(3, "vbclClipboardForwardToHost: %d\n", fFormats);
279
280 /* Walk across all item(s) formats */
281 uint32_t fFormatsLeft = fFormats;
282 while (fFormatsLeft)
283 {
284 if (fFormatsLeft & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
285 {
286 VBoxClientVerbose(3, "requested VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT: %d\n", fFormats);
287
288 RTUTF16 *pUtf16Str = NULL;
289
290 /* First, try to get UTF16 encoded buffer */
291 rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeUTF16PlainText, &pvData, &cbData, &cbAlloc);
292 if (RT_SUCCESS(rc))
293 {
294 rc = RTUtf16DupEx(&pUtf16Str, (PRTUTF16)pvData, 0);
295 if (RT_FAILURE(rc))
296 pUtf16Str = NULL;
297 }
298 else /* Failed to get UTF16 buffer */
299 {
300 /* Then, try to get UTF8 encoded buffer */
301 rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeUTF8PlainText, &pvData, &cbData, &cbAlloc);
302 if (RT_SUCCESS(rc))
303 {
304 rc = RTStrToUtf16((const char *)pvData, &pUtf16Str);
305 if (RT_FAILURE(rc))
306 pUtf16Str = NULL;
307 }
308 }
309
310 /* Finally, we got UTF16 encoded buffer */
311 if (RT_SUCCESS(rc))
312 {
313 rc = vbclClipboardHostPasteText(u32ClientId, (PRTUTF16)pvData, cbData);
314
315 if (pUtf16Str)
316 {
317 RTUtf16Free(pUtf16Str);
318 pUtf16Str = NULL;
319 }
320
321 vbclClipboardReleaseGuestData(&pvData, cbAlloc);
322 }
323 else
324 {
325 /* No data found or error occurred: send empty buffer */
326 rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, NULL, 0);
327 }
328
329 fFormatsLeft &= ~(uint32_t)VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
330 }
331
332 else if (fFormatsLeft & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
333 {
334 VBoxClientVerbose(3, "requested VBOX_SHARED_CLIPBOARD_FMT_BITMAP: %d\n", fFormats);
335
336 rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeBMP, &pvData, &cbData, &cbAlloc);
337 if (RT_SUCCESS(rc))
338 {
339 rc = vbclClipboardHostPasteBitmap(u32ClientId, pvData, cbData);
340 vbclClipboardReleaseGuestData(&pvData, cbAlloc);
341 }
342 else
343 {
344 /* No data found or error occurred: send empty buffer */
345 rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHARED_CLIPBOARD_FMT_BITMAP, NULL, 0);
346 }
347
348 fFormatsLeft &= ~(uint32_t)VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
349 }
350
351 else if (fFormatsLeft & VBOX_SHARED_CLIPBOARD_FMT_HTML)
352 {
353 VBoxClientVerbose(3, "requested VBOX_SHARED_CLIPBOARD_FMT_HTML: %d\n", fFormats);
354
355 rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeHTML, &pvData, &cbData, &cbAlloc);
356 if (RT_SUCCESS(rc))
357 {
358 rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHARED_CLIPBOARD_FMT_HTML, pvData, cbData);
359 vbclClipboardReleaseGuestData(&pvData, cbAlloc);
360 }
361 else
362 {
363 /* No data found or error occurred: send empty buffer */
364 rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHARED_CLIPBOARD_FMT_HTML, NULL, 0);
365 }
366
367 fFormatsLeft &= ~(uint32_t)VBOX_SHARED_CLIPBOARD_FMT_HTML;
368 }
369
370 else
371 {
372 VBoxClientVerbose(3, "requested data in unsupported format: %#x\n", fFormatsLeft);
373 break;
374 }
375 }
376
377 return rc; /** @todo r=bird: If there are multiple formats available, which rc is returned here? Does it matter? */
378}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette