VirtualBox

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

Last change on this file was 103148, checked in by vboxsync, 5 months ago

HostServices/SharedClipboard: Some warning fixes about externally visible functions which should be static, bugref:3409

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

© 2023 Oracle
ContactPrivacy policyTerms of Use