VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/darwin-pasteboard.cpp@ 103131

Last change on this file since 103131 was 100108, checked in by vboxsync, 16 months ago

*: Fix build issues when setting VBOX_WITH_WARNINGS_AS_ERRORS=1 on darwin.arm64 and make it a default, bugref:10469

  • Property eol-style set to native
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.9 KB
Line 
1/* $Id: darwin-pasteboard.cpp 100108 2023-06-07 20:05:13Z vboxsync $ */
2/** @file
3 * Shared Clipboard Service - Mac OS X host implementation.
4 */
5
6/*
7 * Includes contributions from François Revol
8 *
9 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
10 *
11 * This file is part of VirtualBox base platform packages, as
12 * available from https://www.virtualbox.org.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation, in version 3 of the
17 * License.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses>.
26 *
27 * SPDX-License-Identifier: GPL-3.0-only
28 */
29
30
31/*********************************************************************************************************************************
32* Header Files *
33*********************************************************************************************************************************/
34#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
35#include <Carbon/Carbon.h>
36
37#include <iprt/assert.h>
38#include <iprt/mem.h>
39#include <iprt/errcore.h>
40#include <iprt/utf16.h>
41
42#include <VBox/log.h>
43#include <VBox/HostServices/VBoxClipboardSvc.h>
44#include <VBox/GuestHost/SharedClipboard.h>
45#include <VBox/GuestHost/clipboard-helper.h>
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51#define WITH_HTML_H2G 1
52#define WITH_HTML_G2H 1
53
54RT_GCC_NO_WARN_DEPRECATED_BEGIN /* Much here is deprecated since 12.0 */
55
56/* For debugging */
57//#define SHOW_CLIPBOARD_CONTENT
58
59
60/**
61 * Initialize the global pasteboard and return a reference to it.
62 *
63 * @param pPasteboardRef Reference to the global pasteboard.
64 *
65 * @returns IPRT status code.
66 */
67int initPasteboard(PasteboardRef *pPasteboardRef)
68{
69 int rc = VINF_SUCCESS;
70
71 if (PasteboardCreate(kPasteboardClipboard, pPasteboardRef))
72 rc = VERR_NOT_SUPPORTED;
73
74 return rc;
75}
76
77/**
78 * Release the reference to the global pasteboard.
79 *
80 * @param pPasteboardRef Reference to the global pasteboard.
81 */
82void destroyPasteboard(PasteboardRef *pPasteboardRef)
83{
84 CFRelease(*pPasteboardRef);
85 *pPasteboardRef = NULL;
86}
87
88/**
89 * Inspect the global pasteboard for new content. Check if there is some type
90 * that is supported by vbox and return it.
91 *
92 * @param hPasteboard Reference to the global pasteboard.
93 * @param idOwnership Our ownership ID.
94 * @param hStrOwnershipFlavor The ownership flavor string reference returned
95 * by takePasteboardOwnership().
96 * @param pfFormats Pointer for the bit combination of the
97 * supported types.
98 * @param pfChanged True if something has changed after the
99 * last call.
100 *
101 * @returns VINF_SUCCESS.
102 */
103int queryNewPasteboardFormats(PasteboardRef hPasteboard, uint64_t idOwnership, void *hStrOwnershipFlavor,
104 uint32_t *pfFormats, bool *pfChanged)
105{
106 OSStatus orc;
107
108 *pfFormats = 0;
109 *pfChanged = true;
110
111 PasteboardSyncFlags syncFlags;
112 /* Make sure all is in sync */
113 syncFlags = PasteboardSynchronize(hPasteboard);
114 /* If nothing changed return */
115 if (!(syncFlags & kPasteboardModified))
116 {
117 *pfChanged = false;
118 Log2(("queryNewPasteboardFormats: no change\n"));
119 return VINF_SUCCESS;
120 }
121
122 /* Are some items in the pasteboard? */
123 ItemCount cItems = 0;
124 orc = PasteboardGetItemCount(hPasteboard, &cItems);
125 if (orc == 0)
126 {
127 if (cItems < 1)
128 Log(("queryNewPasteboardFormats: changed: No items on the pasteboard\n"));
129 else
130 {
131 /* The id of the first element in the pasteboard */
132 PasteboardItemID idItem = 0;
133 orc = PasteboardGetItemIdentifier(hPasteboard, 1, &idItem);
134 if (orc == 0)
135 {
136 /*
137 * Retrieve all flavors on the pasteboard, maybe there
138 * is something we can use. Or maybe we're the owner.
139 */
140 CFArrayRef hFlavors = 0;
141 orc = PasteboardCopyItemFlavors(hPasteboard, idItem, &hFlavors);
142 if (orc == 0)
143 {
144 CFIndex cFlavors = CFArrayGetCount(hFlavors);
145 for (CFIndex idxFlavor = 0; idxFlavor < cFlavors; idxFlavor++)
146 {
147 CFStringRef hStrFlavor = (CFStringRef)CFArrayGetValueAtIndex(hFlavors, idxFlavor);
148 if ( idItem == (PasteboardItemID)idOwnership
149 && hStrOwnershipFlavor
150 && CFStringCompare(hStrFlavor, (CFStringRef)hStrOwnershipFlavor, 0) == kCFCompareEqualTo)
151 {
152 /* We made the changes ourselves. */
153 Log2(("queryNewPasteboardFormats: no-changed: our clipboard!\n"));
154 *pfChanged = false;
155 *pfFormats = 0;
156 break;
157 }
158
159 if (UTTypeConformsTo(hStrFlavor, kUTTypeBMP))
160 {
161 Log(("queryNewPasteboardFormats: BMP flavor detected.\n"));
162 *pfFormats |= VBOX_SHCL_FMT_BITMAP;
163 }
164 else if ( UTTypeConformsTo(hStrFlavor, kUTTypeUTF8PlainText)
165 || UTTypeConformsTo(hStrFlavor, kUTTypeUTF16PlainText))
166 {
167 Log(("queryNewPasteboardFormats: Unicode flavor detected.\n"));
168 *pfFormats |= VBOX_SHCL_FMT_UNICODETEXT;
169 }
170#ifdef WITH_HTML_H2G
171 else if (UTTypeConformsTo(hStrFlavor, kUTTypeHTML))
172 {
173 Log(("queryNewPasteboardFormats: HTML flavor detected.\n"));
174 *pfFormats |= VBOX_SHCL_FMT_HTML;
175 }
176#endif
177#ifdef LOG_ENABLED
178 else if (LogIs2Enabled())
179 {
180 if (CFStringGetCharactersPtr(hStrFlavor))
181 Log2(("queryNewPasteboardFormats: Unknown flavor: %ls.\n", CFStringGetCharactersPtr(hStrFlavor)));
182 else if (CFStringGetCStringPtr(hStrFlavor, kCFStringEncodingUTF8))
183 Log2(("queryNewPasteboardFormats: Unknown flavor: %s.\n",
184 CFStringGetCStringPtr(hStrFlavor, kCFStringEncodingUTF8)));
185 else
186 Log2(("queryNewPasteboardFormats: Unknown flavor: ???\n"));
187 }
188#endif
189 }
190
191 CFRelease(hFlavors);
192 }
193 else
194 Log(("queryNewPasteboardFormats: PasteboardCopyItemFlavors failed - %d (%#x)\n", orc, orc));
195 }
196 else
197 Log(("queryNewPasteboardFormats: PasteboardGetItemIdentifier failed - %d (%#x)\n", orc, orc));
198
199 if (*pfChanged)
200 Log(("queryNewPasteboardFormats: changed: *pfFormats=%#x\n", *pfFormats));
201 }
202 }
203 else
204 Log(("queryNewPasteboardFormats: PasteboardGetItemCount failed - %d (%#x)\n", orc, orc));
205 return VINF_SUCCESS;
206}
207
208/**
209 * Read content from the host clipboard and write it to the internal clipboard
210 * structure for further processing.
211 *
212 * @param pPasteboard Reference to the global pasteboard.
213 * @param fFormat The format type which should be read.
214 * @param pv The destination buffer.
215 * @param cb The size of the destination buffer.
216 * @param pcbActual The size which is needed to transfer the content.
217 *
218 * @returns IPRT status code.
219 */
220int readFromPasteboard(PasteboardRef pPasteboard, uint32_t fFormat, void *pv, uint32_t cb, uint32_t *pcbActual)
221{
222 Log(("readFromPasteboard: fFormat = %02X\n", fFormat));
223
224 /* Make sure all is in sync */
225 PasteboardSynchronize(pPasteboard);
226
227 /* Are some items in the pasteboard? */
228 ItemCount cItems;
229 OSStatus orc = PasteboardGetItemCount(pPasteboard, &cItems);
230 if (cItems < 1)
231 return VINF_SUCCESS;
232
233 /*
234 * Our default response...
235 */
236 int rc = VERR_NOT_SUPPORTED;
237
238 /*
239 * The id of the first element in the pasteboard
240 */
241 PasteboardItemID idItem;
242 orc = PasteboardGetItemIdentifier(pPasteboard, 1, &idItem);
243 if (orc == 0)
244 {
245 CFDataRef hDataCopy = 0;
246 size_t cbDataCopy = 0;
247
248 /*
249 * The guest request unicode
250 */
251 if (fFormat & VBOX_SHCL_FMT_UNICODETEXT)
252 {
253 PRTUTF16 pwszSrcFree = NULL;
254 PCRTUTF16 pwszSrc = NULL;
255 size_t cwcSrc = 0;
256
257 /* First preference is plain UTF-16 text: */
258 orc = PasteboardCopyItemFlavorData(pPasteboard, idItem, kUTTypeUTF16PlainText, &hDataCopy);
259 if (orc == 0)
260 {
261 cbDataCopy = CFDataGetLength(hDataCopy);
262 Log(("Clipboard content is utf-16 (%zu bytes)\n", cbDataCopy));
263 pwszSrc = (PCRTUTF16)CFDataGetBytePtr(hDataCopy);
264 if (pwszSrc)
265 {
266 cwcSrc = RTUtf16NLen(pwszSrc, cbDataCopy / sizeof(RTUTF16));
267 if (cwcSrc >= cbDataCopy / sizeof(RTUTF16))
268 {
269 pwszSrcFree = RTUtf16Alloc((cwcSrc + 1) * sizeof(RTUTF16));
270 if (pwszSrcFree)
271 {
272 memcpy(pwszSrcFree, pwszSrc, cwcSrc * sizeof(RTUTF16));
273 pwszSrcFree[cwcSrc] = '\0';
274 pwszSrc = pwszSrcFree;
275 }
276 else
277 {
278 rc = VERR_NO_UTF16_MEMORY;
279 pwszSrc = NULL;
280 }
281 }
282 }
283 else
284 rc = VERR_GENERAL_FAILURE;
285 }
286 /* Second preference is plain UTF-8 text: */
287 else
288 {
289 orc = PasteboardCopyItemFlavorData(pPasteboard, idItem, kUTTypeUTF8PlainText, &hDataCopy);
290 if (orc == 0)
291 {
292 cbDataCopy = CFDataGetLength(hDataCopy);
293 Log(("readFromPasteboard: clipboard content is utf-8 (%zu bytes)\n", cbDataCopy));
294 const char *pszSrc = (const char *)CFDataGetBytePtr(hDataCopy);
295 if (pszSrc)
296 {
297 size_t cchSrc = RTStrNLen(pszSrc, cbDataCopy);
298 rc = RTStrToUtf16Ex(pszSrc, cchSrc, &pwszSrcFree, 0, &cwcSrc);
299 if (RT_SUCCESS(rc))
300 pwszSrc = pwszSrcFree;
301 }
302 else
303 rc = VERR_GENERAL_FAILURE;
304 }
305 }
306 if (pwszSrc)
307 {
308 /*
309 * Convert to windows UTF-16.
310 */
311 Assert(cwcSrc == RTUtf16Len(pwszSrc));
312 size_t cwcDst = 0;
313 rc = ShClUtf16LFLenUtf8(pwszSrc, cwcSrc, &cwcDst);
314 if (RT_SUCCESS(rc))
315 {
316 cwcDst++; /* Add space for terminator. */
317
318 *pcbActual = cwcDst * sizeof(RTUTF16);
319 if (*pcbActual <= cb)
320 {
321 rc = ShClConvUtf16LFToCRLF(pwszSrc, cwcSrc, (PRTUTF16)pv, cb / sizeof(RTUTF16));
322 if (RT_SUCCESS(rc))
323 {
324#ifdef SHOW_CLIPBOARD_CONTENT
325 Log(("readFromPasteboard: clipboard content: %ls\n", (PCRTUTF16)pv));
326#endif
327 }
328 else
329 {
330 Log(("readFromPasteboard: ShClUtf16LinToWin failed - %Rrc!\n", rc));
331 AssertRC(rc);
332 }
333 }
334 else
335 {
336 Log(("readFromPasteboard: Insufficient (text) buffer space: %#zx, need %#zx\n", cb, *pcbActual));
337 rc = VINF_SUCCESS;
338 }
339 }
340 else
341 {
342 Log(("readFromPasteboard: ShClUtf16GetWinSize failed - %Rrc!\n", rc));
343 AssertRC(rc);
344 }
345 RTUtf16Free(pwszSrcFree);
346 }
347 }
348 /*
349 * The guest request BITMAP
350 */
351 else if (fFormat & VBOX_SHCL_FMT_BITMAP)
352 {
353 /* Get the BMP data from the pasteboard */
354 orc = PasteboardCopyItemFlavorData(pPasteboard, idItem, kUTTypeBMP, &hDataCopy);
355 if (orc == 0)
356 {
357 cbDataCopy = CFDataGetLength(hDataCopy);
358 Log(("Clipboard content is BMP (%zu bytes)\n", cbDataCopy));
359 const void *pvSrc = CFDataGetBytePtr(hDataCopy);
360 if (pvSrc)
361 {
362 /*
363 * Try get the device independent bitmap (DIB) bit from it.
364 */
365 const void *pvDib;
366 size_t cbDib;
367 rc = ShClBmpGetDib(pvSrc, cbDataCopy, &pvDib, &cbDib);
368 if (RT_SUCCESS(rc))
369 {
370 *pcbActual = cbDib;
371 if (*pcbActual <= cb)
372 {
373 memcpy(pv, pvDib, cbDib);
374#ifdef SHOW_CLIPBOARD_CONTENT
375 Log(("readFromPasteboard: clipboard content bitmap %zx bytes\n", cbDib));
376#endif
377 }
378 else
379 Log(("readFromPasteboard: Insufficient (bitmap) buffer space: %#zx, need %#zx\n", cb, cbDib));
380 rc = VINF_SUCCESS;
381 }
382 else
383 {
384 AssertRC(rc);
385 Log(("readFromPasteboard: ShClBmpGetDib failed - %Rrc - unknown bitmap format??\n", rc));
386 rc = VERR_NOT_SUPPORTED;
387 }
388 }
389 else
390 rc = VERR_GENERAL_FAILURE;
391 }
392 else
393 LogFlow(("readFromPasteboard: PasteboardCopyItemFlavorData/kUTTypeBMP -> %d (%#x)\n", orc, orc));
394 }
395#ifdef WITH_HTML_H2G
396 /*
397 * The guest request HTML. It expects a UTF-8 reply and we assume
398 * that's what's on the pasteboard too.
399 */
400 else if (fFormat & VBOX_SHCL_FMT_HTML)
401 {
402 orc = PasteboardCopyItemFlavorData(pPasteboard, idItem, kUTTypeHTML, &hDataCopy);
403 if (orc == 0)
404 {
405 cbDataCopy = CFDataGetLength(hDataCopy);
406 Log(("Clipboard content is HTML (%zu bytes):\n", cbDataCopy));
407 const char *pszSrc = (const char *)CFDataGetBytePtr(hDataCopy);
408 if (pszSrc)
409 {
410 Log3(("%.*Rhxd\n", cbDataCopy, pszSrc));
411 rc = RTStrValidateEncodingEx(pszSrc, cbDataCopy, 0 /*fFlags*/);
412 if (RT_SUCCESS(rc))
413 {
414 size_t cchSrc = RTStrNLen(pszSrc, cbDataCopy);
415 *pcbActual = cchSrc;
416 if (cchSrc <= cb)
417 memcpy(pv, pszSrc, cchSrc);
418 else
419 Log(("readFromPasteboard: Insufficient (HTML) buffer space: %#zx, need %#zx\n", cb, cchSrc));
420 rc = VINF_SUCCESS;
421 }
422 else
423 {
424 Log(("readFromPasteboard: Invalid UTF-8 encoding on pasteboard: %Rrc\n", rc));
425 rc = VERR_NOT_SUPPORTED;
426 }
427 }
428 else
429 rc = VERR_GENERAL_FAILURE;
430 }
431 else
432 LogFlow(("readFromPasteboard: PasteboardCopyItemFlavorData/kUTTypeHTML -> %d (%#x)\n", orc, orc));
433 }
434#endif
435 else
436 {
437 Log2(("readFromPasteboard: Unsupported format: %#x\n", fFormat));
438 rc = VERR_NOT_SUPPORTED;
439 }
440
441 /*
442 * Release the data copy, if we got one. There are no returns above!
443 */
444 if (hDataCopy)
445 CFRelease(hDataCopy);
446 }
447 else
448 {
449 Log(("readFromPasteboard: PasteboardGetItemIdentifier failed: %u (%#x)\n", orc, orc));
450 rc = VERR_NOT_SUPPORTED;
451 }
452
453 Log(("readFromPasteboard: rc=%Rrc *pcbActual=%#zx\n", rc, *pcbActual));
454 return rc;
455}
456
457/**
458 * Takes the ownership of the pasteboard.
459 *
460 * This is called when the other end reports available formats.
461 *
462 * @returns VBox status code.
463 * @param hPasteboard The pastboard handle (reference).
464 * @param idOwnership The ownership ID to use now.
465 * @param pszOwnershipFlavor The ownership indicator flavor
466 * @param pszOwnershipValue The ownership value (stringified format mask).
467 * @param phStrOwnershipFlavor Pointer to a CFStringRef variable holding
468 * the current ownership flavor string. This
469 * will always be released, and set again on
470 * success.
471 *
472 * @todo Add fFormats so we can make promises about available formats at once
473 * without needing to request any data first. That might help on
474 * flavor priority.
475 */
476int takePasteboardOwnership(PasteboardRef hPasteboard, uint64_t idOwnership, const char *pszOwnershipFlavor,
477 const char *pszOwnershipValue, void **phStrOwnershipFlavor)
478{
479 /*
480 * Release the old string.
481 */
482 if (*phStrOwnershipFlavor)
483 {
484 CFStringRef hOldFlavor = (CFStringRef)*phStrOwnershipFlavor;
485 CFRelease(hOldFlavor);
486 *phStrOwnershipFlavor = NULL;
487 }
488
489 /*
490 * Clear the pasteboard and take ownership over it.
491 */
492 OSStatus orc = PasteboardClear(hPasteboard);
493 if (orc == 0)
494 {
495 /* For good measure. */
496 PasteboardSynchronize(hPasteboard);
497
498 /*
499 * Put the ownership flavor and value onto the clipboard.
500 */
501 CFDataRef hData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)pszOwnershipValue, strlen(pszOwnershipValue));
502 if (hData)
503 {
504 CFStringRef hFlavor = CFStringCreateWithCString(kCFAllocatorDefault, pszOwnershipFlavor, kCFStringEncodingUTF8);
505 if (hFlavor)
506 {
507 orc = PasteboardPutItemFlavor(hPasteboard, (PasteboardItemID)idOwnership,
508 hFlavor, hData, kPasteboardFlavorNoFlags);
509 if (orc == 0)
510 {
511 *phStrOwnershipFlavor = (void *)hFlavor;
512 Log(("takePasteboardOwnership: idOwnership=%RX64 flavor=%s value=%s\n",
513 idOwnership, pszOwnershipFlavor, pszOwnershipValue));
514 }
515 else
516 {
517 Log(("takePasteboardOwnership: PasteboardPutItemFlavor -> %d (%#x)!\n", orc, orc));
518 CFRelease(hFlavor);
519 }
520 }
521 else
522 Log(("takePasteboardOwnership: CFStringCreateWithCString failed!\n"));
523 CFRelease(hData);
524 }
525 else
526 Log(("takePasteboardOwnership: CFDataCreate failed!\n"));
527 }
528 else
529 Log(("takePasteboardOwnership: PasteboardClear failed -> %d (%#x)\n", orc, orc));
530 return orc == 0 ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
531}
532
533/**
534 * Write clipboard content to the host clipboard from the internal clipboard
535 * structure.
536 *
537 * @param hPasteboard Reference to the global pasteboard.
538 * @param idOwnership The ownership ID.
539 * @param pv The source buffer.
540 * @param cb The size of the source buffer.
541 * @param fFormat The format type which should be written.
542 *
543 * @returns IPRT status code.
544 */
545int writeToPasteboard(PasteboardRef hPasteboard, uint64_t idOwnership, const void *pv, uint32_t cb, uint32_t fFormat)
546{
547 int rc;
548 OSStatus orc;
549 CFDataRef hData;
550 Log(("writeToPasteboard: fFormat=%#x\n", fFormat));
551
552 /* Make sure all is in sync */
553 PasteboardSynchronize(hPasteboard);
554
555 /*
556 * Handle the unicode text
557 */
558 if (fFormat & VBOX_SHCL_FMT_UNICODETEXT)
559 {
560 PCRTUTF16 const pwszSrc = (PCRTUTF16)pv;
561 size_t const cwcSrc = cb / sizeof(RTUTF16);
562
563 /*
564 * If the other side is windows or OS/2, we may have to convert
565 * '\r\n' -> '\n' and the drop ending marker.
566 */
567
568 /* How long will the converted text be? */
569 size_t cwcDst = 0;
570 rc = ShClUtf16CRLFLenUtf8(pwszSrc, cwcSrc, &cwcDst);
571 AssertMsgRCReturn(rc, ("ShClUtf16GetLinSize failed: %Rrc\n", rc), rc);
572
573 /* Ignore empty strings? */ /** @todo r=andy Really? Why? */
574 if (cwcDst == 0)
575 {
576 Log(("writeToPasteboard: received empty string from the guest; ignoreing it.\n"));
577 return VINF_SUCCESS;
578 }
579
580 cwcDst++; /* Add space for terminator. */
581
582 /* Allocate the necessary memory and do the conversion. */
583 PRTUTF16 pwszDst = (PRTUTF16)RTMemAlloc(cwcDst * sizeof(RTUTF16));
584 AssertMsgReturn(pwszDst, ("cwcDst=%#zx\n", cwcDst), VERR_NO_UTF16_MEMORY);
585
586 rc = ShClConvUtf16CRLFToLF(pwszSrc, cwcSrc, pwszDst, cwcDst);
587 if (RT_SUCCESS(rc))
588 {
589 /*
590 * Create an immutable CFData object that we can place on the clipboard.
591 */
592 hData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)pwszDst, cwcDst * sizeof(RTUTF16));
593 if (hData)
594 {
595 orc = PasteboardPutItemFlavor(hPasteboard, (PasteboardItemID)idOwnership,
596 kUTTypeUTF16PlainText, hData, kPasteboardFlavorNoFlags);
597 if (orc == 0)
598 rc = VINF_SUCCESS;
599 else
600 {
601 Log(("writeToPasteboard: PasteboardPutItemFlavor/kUTTypeUTF16PlainText failed: %d (%#x)\n", orc, orc));
602 rc = VERR_GENERAL_FAILURE;
603 }
604 CFRelease(hData);
605 }
606 else
607 {
608 Log(("writeToPasteboard: CFDataCreate/UTF16 failed!\n"));
609 rc = VERR_NO_MEMORY;
610 }
611
612 /*
613 * Now for the UTF-8 version.
614 */
615 char *pszDst;
616 int rc2 = RTUtf16ToUtf8(pwszDst, &pszDst);
617 if (RT_SUCCESS(rc2))
618 {
619 hData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)pszDst, strlen(pszDst));
620 if (hData)
621 {
622 orc = PasteboardPutItemFlavor(hPasteboard, (PasteboardItemID)idOwnership,
623 kUTTypeUTF8PlainText, hData, kPasteboardFlavorNoFlags);
624 if (orc != 0)
625 {
626 Log(("writeToPasteboard: PasteboardPutItemFlavor/kUTTypeUTF8PlainText failed: %d (%#x)\n", orc, orc));
627 rc = VERR_GENERAL_FAILURE;
628 }
629 CFRelease(hData);
630 }
631 else
632 {
633 Log(("writeToPasteboard: CFDataCreate/UTF8 failed!\n"));
634 rc = VERR_NO_MEMORY;
635 }
636 RTStrFree(pszDst);
637 }
638 else
639 rc = rc2;
640 }
641 else
642 Log(("writeToPasteboard: clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc));
643
644 RTMemFree(pwszDst);
645 }
646 /*
647 * Handle the bitmap. We convert the DIB to a bitmap and put it on
648 * the pasteboard using the BMP flavor.
649 */
650 else if (fFormat & VBOX_SHCL_FMT_BITMAP)
651 {
652 /* Create a full BMP from it */
653 void *pvBmp;
654 size_t cbBmp;
655 rc = ShClDibToBmp(pv, cb, &pvBmp, &cbBmp);
656 if (RT_SUCCESS(rc))
657 {
658 hData = CFDataCreate(kCFAllocatorDefault, (UInt8 const *)pvBmp, cbBmp);
659 if (hData)
660 {
661 orc = PasteboardPutItemFlavor(hPasteboard, (PasteboardItemID)idOwnership,
662 kUTTypeBMP, hData, kPasteboardFlavorNoFlags);
663 if (orc != 0)
664 {
665 Log(("writeToPasteboard: PasteboardPutItemFlavor/kUTTypeBMP failed: %d (%#x)\n", orc, orc));
666 rc = VERR_GENERAL_FAILURE;
667 }
668 CFRelease(hData);
669 }
670 else
671 {
672 Log(("writeToPasteboard: CFDataCreate/UTF8 failed!\n"));
673 rc = VERR_NO_MEMORY;
674 }
675 RTMemFree(pvBmp);
676 }
677 }
678#ifdef WITH_HTML_G2H
679 /*
680 * Handle HTML. Expect UTF-8, ignore line endings and just put it
681 * straigh up on the pasteboard for now.
682 */
683 else if (fFormat & VBOX_SHCL_FMT_HTML)
684 {
685 const char *pszSrc = (const char *)pv;
686 size_t const cchSrc = RTStrNLen(pszSrc, cb);
687 rc = RTStrValidateEncodingEx(pszSrc, cchSrc, 0);
688 if (RT_SUCCESS(rc))
689 {
690 hData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)pszSrc, cchSrc);
691 if (hData)
692 {
693 orc = PasteboardPutItemFlavor(hPasteboard, (PasteboardItemID)idOwnership, kUTTypeHTML,
694 hData, kPasteboardFlavorNoFlags);
695 if (orc == 0)
696 rc = VINF_SUCCESS;
697 else
698 {
699 Log(("writeToPasteboard: PasteboardPutItemFlavor/kUTTypeHTML failed: %d (%#x)\n", orc, orc));
700 rc = VERR_GENERAL_FAILURE;
701 }
702 CFRelease(hData);
703 }
704 else
705 {
706 Log(("writeToPasteboard: CFDataCreate/HTML failed!\n"));
707 rc = VERR_NO_MEMORY;
708 }
709 }
710 else
711 Log(("writeToPasteboard: HTML: Invalid UTF-8 encoding: %Rrc\n", rc));
712 }
713#endif
714 else
715 rc = VERR_NOT_IMPLEMENTED;
716
717 Log(("writeToPasteboard: rc=%Rrc\n", rc));
718 return rc;
719}
720
721RT_GCC_NO_WARN_DEPRECATED_END
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