VirtualBox

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

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