VirtualBox

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

Last change on this file since 94769 was 93115, checked in by vboxsync, 3 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.2 KB
Line 
1/** $Id: VBoxClientClipboardGuestToHost.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VBoxClient - Shared Clipboard Guest -> Host copying, Darwin.
4 */
5
6/*
7 * Copyright (C) 2007-2022 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_SHCL_FMT_UNICODETEXT);
70 VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeUTF8PlainText, VBOX_SHCL_FMT_UNICODETEXT);
71 VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeBMP, VBOX_SHCL_FMT_BITMAP );
72 VBOXCL_ADD_FORMAT_IF_PRESENT(kUTTypeHTML, VBOX_SHCL_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 cwcTmp; /* (includes a schwarzenegger character) */
224 int rc = ShClUtf16LFLenUtf8(pwszData, cbData / sizeof(RTUTF16), &cwcTmp);
225 AssertRCReturn(rc, rc);
226
227 cwcTmp++; /* Add space for terminator. */
228
229 PRTUTF16 pwszTmp = (PRTUTF16)RTMemAlloc(cwcTmp * sizeof(RTUTF16));
230 AssertReturn(pwszTmp, VERR_NO_MEMORY);
231
232 rc = ShClConvUtf16LFToCRLF(pwszData, cbData / sizeof(RTUTF16), pwszTmp, cwcTmp);
233 if (RT_SUCCESS(rc))
234 rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHCL_FMT_UNICODETEXT,
235 pwszTmp, cwcTmp * sizeof(RTUTF16));
236
237 RTMemFree(pwszTmp);
238
239 return rc;
240}
241
242
243/**
244 * Paste a bitmap onto the host clipboard.
245 *
246 * @param u32ClientId Host clipboard connection.
247 * @param pvData The bitmap data.
248 * @param cbData The size of the bitmap.
249 */
250static int vbclClipboardHostPasteBitmap(uint32_t u32ClientId, void *pvData, uint32_t cbData)
251{
252 const void *pvDib;
253 size_t cbDib;
254 int rc = ShClBmpGetDib(pvData, cbData, &pvDib, &cbDib);
255 AssertRCReturn(rc, rc);
256
257 rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHCL_FMT_BITMAP, pvDib, cbDib);
258
259 return rc;
260}
261
262
263/**
264 * Read guest's clipboard buffer and forward its content to host.
265 *
266 * @param u32ClientId Host clipboard connection.
267 * @param pPasteboard Guest PasteBoard reference.
268 * @param fFormats List of data formats (bit field) received from host.
269 *
270 * @returns IPRT status code.
271 */
272int vbclClipboardForwardToHost(uint32_t u32ClientId, PasteboardRef pPasteboard, uint32_t fFormats)
273{
274 int rc = VINF_SUCCESS;
275
276 void *pvData = NULL;
277 uint32_t cbData = 0;
278 uint32_t cbAlloc = 0;
279
280 VBoxClientVerbose(3, "vbclClipboardForwardToHost: %d\n", fFormats);
281
282 /* Walk across all item(s) formats */
283 uint32_t fFormatsLeft = fFormats;
284 while (fFormatsLeft)
285 {
286 if (fFormatsLeft & VBOX_SHCL_FMT_UNICODETEXT)
287 {
288 VBoxClientVerbose(3, "requested VBOX_SHCL_FMT_UNICODETEXT: %d\n", fFormats);
289
290 RTUTF16 *pUtf16Str = NULL;
291
292 /* First, try to get UTF16 encoded buffer */
293 rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeUTF16PlainText, &pvData, &cbData, &cbAlloc);
294 if (RT_SUCCESS(rc))
295 {
296 rc = RTUtf16DupEx(&pUtf16Str, (PRTUTF16)pvData, 0);
297 if (RT_FAILURE(rc))
298 pUtf16Str = NULL;
299 }
300 else /* Failed to get UTF16 buffer */
301 {
302 /* Then, try to get UTF8 encoded buffer */
303 rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeUTF8PlainText, &pvData, &cbData, &cbAlloc);
304 if (RT_SUCCESS(rc))
305 {
306 rc = RTStrToUtf16((const char *)pvData, &pUtf16Str);
307 if (RT_FAILURE(rc))
308 pUtf16Str = NULL;
309 }
310 }
311
312 /* Finally, we got UTF16 encoded buffer */
313 if (RT_SUCCESS(rc))
314 {
315 rc = vbclClipboardHostPasteText(u32ClientId, (PRTUTF16)pvData, cbData);
316
317 if (pUtf16Str)
318 {
319 RTUtf16Free(pUtf16Str);
320 pUtf16Str = NULL;
321 }
322
323 vbclClipboardReleaseGuestData(&pvData, cbAlloc);
324 }
325 else
326 {
327 /* No data found or error occurred: send empty buffer */
328 rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHCL_FMT_UNICODETEXT, NULL, 0);
329 }
330
331 fFormatsLeft &= ~(uint32_t)VBOX_SHCL_FMT_UNICODETEXT;
332 }
333
334 else if (fFormatsLeft & VBOX_SHCL_FMT_BITMAP)
335 {
336 VBoxClientVerbose(3, "requested VBOX_SHCL_FMT_BITMAP: %d\n", fFormats);
337
338 rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeBMP, &pvData, &cbData, &cbAlloc);
339 if (RT_SUCCESS(rc))
340 {
341 rc = vbclClipboardHostPasteBitmap(u32ClientId, pvData, cbData);
342 vbclClipboardReleaseGuestData(&pvData, cbAlloc);
343 }
344 else
345 {
346 /* No data found or error occurred: send empty buffer */
347 rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHCL_FMT_BITMAP, NULL, 0);
348 }
349
350 fFormatsLeft &= ~(uint32_t)VBOX_SHCL_FMT_BITMAP;
351 }
352
353 else if (fFormatsLeft & VBOX_SHCL_FMT_HTML)
354 {
355 VBoxClientVerbose(3, "requested VBOX_SHCL_FMT_HTML: %d\n", fFormats);
356
357 rc = vbclClipboardReadGuestData(pPasteboard, kUTTypeHTML, &pvData, &cbData, &cbAlloc);
358 if (RT_SUCCESS(rc))
359 {
360 rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHCL_FMT_HTML, pvData, cbData);
361 vbclClipboardReleaseGuestData(&pvData, cbAlloc);
362 }
363 else
364 {
365 /* No data found or error occurred: send empty buffer */
366 rc = vbclClipboardHostPasteData(u32ClientId, VBOX_SHCL_FMT_HTML, NULL, 0);
367 }
368
369 fFormatsLeft &= ~(uint32_t)VBOX_SHCL_FMT_HTML;
370 }
371
372 else
373 {
374 VBoxClientVerbose(3, "requested data in unsupported format: %#x\n", fFormatsLeft);
375 break;
376 }
377 }
378
379 return rc; /** @todo r=bird: If there are multiple formats available, which rc is returned here? Does it matter? */
380}
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