VirtualBox

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

Last change on this file since 100063 was 98103, checked in by vboxsync, 22 months ago

Copyright year updates by scm.

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