VirtualBox

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

Last change on this file since 85845 was 85845, checked in by vboxsync, 4 years ago

Shared Clipboard/X11: Fixes for empty strings (was too strict before), don't include the terminating zeros when return string lengths to match IPRT. Also should fix the testcases.

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