VirtualBox

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

Last change on this file since 99253 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

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