VirtualBox

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

Last change on this file since 72028 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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