VirtualBox

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

Last change on this file since 84411 was 83634, checked in by vboxsync, 5 years ago

SharedClipboard: Figured out the problem with guest -> host HTML, fixed and enabled HTML in both directions. bugref:9620

  • 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.3 KB
Line 
1/* $Id: darwin-pasteboard.cpp 83634 2020-04-09 00:30:32Z 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 = ShClUtf16GetWinSize(pwszSrc, cwcSrc, &cwcDst);
302 if (RT_SUCCESS(rc))
303 {
304 *pcbActual = cwcDst * sizeof(RTUTF16);
305 if (*pcbActual <= cb)
306 {
307 rc = ShClUtf16LinToWin(pwszSrc, cwcSrc, (PRTUTF16)pv, cb / sizeof(RTUTF16));
308 if (RT_SUCCESS(rc))
309 {
310#ifdef SHOW_CLIPBOARD_CONTENT
311 Log(("readFromPasteboard: clipboard content: %ls\n", (PCRTUTF16)pv));
312#endif
313 }
314 else
315 {
316 Log(("readFromPasteboard: ShClUtf16LinToWin failed - %Rrc!\n", rc));
317 AssertRC(rc);
318 }
319 }
320 else
321 {
322 Log(("readFromPasteboard: Insufficient (text) buffer space: %#zx, need %#zx\n", cb, *pcbActual));
323 rc = VINF_SUCCESS;
324 }
325 }
326 else
327 {
328 Log(("readFromPasteboard: ShClUtf16GetWinSize failed - %Rrc!\n", rc));
329 AssertRC(rc);
330 }
331 RTUtf16Free(pwszSrcFree);
332 }
333 }
334 /*
335 * The guest request BITMAP
336 */
337 else if (fFormat & VBOX_SHCL_FMT_BITMAP)
338 {
339 /* Get the BMP data from the pasteboard */
340 orc = PasteboardCopyItemFlavorData(pPasteboard, idItem, kUTTypeBMP, &hDataCopy);
341 if (orc == 0)
342 {
343 cbDataCopy = CFDataGetLength(hDataCopy);
344 Log(("Clipboard content is BMP (%zu bytes)\n", cbDataCopy));
345 const void *pvSrc = CFDataGetBytePtr(hDataCopy);
346 if (pvSrc)
347 {
348 /*
349 * Try get the device independent bitmap (DIB) bit from it.
350 */
351 const void *pvDib;
352 size_t cbDib;
353 rc = ShClBmpGetDib(pvSrc, cbDataCopy, &pvDib, &cbDib);
354 if (RT_SUCCESS(rc))
355 {
356 *pcbActual = cbDib;
357 if (*pcbActual <= cb)
358 {
359 memcpy(pv, pvDib, cbDib);
360#ifdef SHOW_CLIPBOARD_CONTENT
361 Log(("readFromPasteboard: clipboard content bitmap %zx bytes\n", cbDib));
362#endif
363 }
364 else
365 Log(("readFromPasteboard: Insufficient (bitmap) buffer space: %#zx, need %#zx\n", cb, cbDib));
366 rc = VINF_SUCCESS;
367 }
368 else
369 {
370 AssertRC(rc);
371 Log(("readFromPasteboard: ShClBmpGetDib failed - %Rrc - unknown bitmap format??\n", rc));
372 rc = VERR_NOT_SUPPORTED;
373 }
374 }
375 else
376 rc = VERR_GENERAL_FAILURE;
377 }
378 else
379 LogFlow(("readFromPasteboard: PasteboardCopyItemFlavorData/kUTTypeBMP -> %d (%#x)\n", orc, orc));
380 }
381#ifdef WITH_HTML_H2G
382 /*
383 * The guest request HTML. It expects a UTF-8 reply and we assume
384 * that's what's on the pasteboard too.
385 */
386 else if (fFormat & VBOX_SHCL_FMT_HTML)
387 {
388 orc = PasteboardCopyItemFlavorData(pPasteboard, idItem, kUTTypeHTML, &hDataCopy);
389 if (orc == 0)
390 {
391 cbDataCopy = CFDataGetLength(hDataCopy);
392 Log(("Clipboard content is HTML (%zu bytes):\n", cbDataCopy));
393 const char *pszSrc = (const char *)CFDataGetBytePtr(hDataCopy);
394 if (pszSrc)
395 {
396 Log3(("%.*Rhxd\n", cbDataCopy, pszSrc));
397 rc = RTStrValidateEncodingEx(pszSrc, cbDataCopy, 0 /*fFlags*/);
398 if (RT_SUCCESS(rc))
399 {
400 size_t cchSrc = RTStrNLen(pszSrc, cbDataCopy);
401 *pcbActual = cchSrc;
402 if (cchSrc <= cb)
403 memcpy(pv, pszSrc, cchSrc);
404 else
405 Log(("readFromPasteboard: Insufficient (HTML) buffer space: %#zx, need %#zx\n", cb, cchSrc));
406 rc = VINF_SUCCESS;
407 }
408 else
409 {
410 Log(("readFromPasteboard: Invalid UTF-8 encoding on pasteboard: %Rrc\n", rc));
411 rc = VERR_NOT_SUPPORTED;
412 }
413 }
414 else
415 rc = VERR_GENERAL_FAILURE;
416 }
417 else
418 LogFlow(("readFromPasteboard: PasteboardCopyItemFlavorData/kUTTypeHTML -> %d (%#x)\n", orc, orc));
419 }
420#endif
421 else
422 {
423 Log2(("readFromPasteboard: Unsupported format: %#x\n", fFormat));
424 rc = VERR_NOT_SUPPORTED;
425 }
426
427 /*
428 * Release the data copy, if we got one. There are no returns above!
429 */
430 if (hDataCopy)
431 CFRelease(hDataCopy);
432 }
433 else
434 {
435 Log(("readFromPasteboard: PasteboardGetItemIdentifier failed: %u (%#x)\n", orc, orc));
436 rc = VERR_NOT_SUPPORTED;
437 }
438
439 Log(("readFromPasteboard: rc=%Rrc *pcbActual=%#zx\n", rc, *pcbActual));
440 return rc;
441}
442
443/**
444 * Takes the ownership of the pasteboard.
445 *
446 * This is called when the other end reports available formats.
447 *
448 * @returns VBox status code.
449 * @param hPasteboard The pastboard handle (reference).
450 * @param idOwnership The ownership ID to use now.
451 * @param pszOwnershipFlavor The ownership indicator flavor
452 * @param pszOwnershipValue The ownership value (stringified format mask).
453 * @param phStrOwnershipFlavor Pointer to a CFStringRef variable holding
454 * the current ownership flavor string. This
455 * will always be released, and set again on
456 * success.
457 *
458 * @todo Add fFormats so we can make promises about available formats at once
459 * without needing to request any data first. That might help on
460 * flavor priority.
461 */
462int takePasteboardOwnership(PasteboardRef hPasteboard, uint64_t idOwnership, const char *pszOwnershipFlavor,
463 const char *pszOwnershipValue, void **phStrOwnershipFlavor)
464{
465 /*
466 * Release the old string.
467 */
468 if (*phStrOwnershipFlavor)
469 {
470 CFStringRef hOldFlavor = (CFStringRef)*phStrOwnershipFlavor;
471 CFRelease(hOldFlavor);
472 *phStrOwnershipFlavor = NULL;
473 }
474
475 /*
476 * Clear the pasteboard and take ownership over it.
477 */
478 OSStatus orc = PasteboardClear(hPasteboard);
479 if (orc == 0)
480 {
481 /* For good measure. */
482 PasteboardSynchronize(hPasteboard);
483
484 /*
485 * Put the ownership flavor and value onto the clipboard.
486 */
487 CFDataRef hData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)pszOwnershipValue, strlen(pszOwnershipValue));
488 if (hData)
489 {
490 CFStringRef hFlavor = CFStringCreateWithCString(kCFAllocatorDefault, pszOwnershipFlavor, kCFStringEncodingUTF8);
491 if (hFlavor)
492 {
493 orc = PasteboardPutItemFlavor(hPasteboard, (PasteboardItemID)idOwnership,
494 hFlavor, hData, kPasteboardFlavorNoFlags);
495 if (orc == 0)
496 {
497 *phStrOwnershipFlavor = (void *)hFlavor;
498 Log(("takePasteboardOwnership: idOwnership=%RX64 flavor=%s value=%s\n",
499 idOwnership, pszOwnershipFlavor, pszOwnershipValue));
500 }
501 else
502 {
503 Log(("takePasteboardOwnership: PasteboardPutItemFlavor -> %d (%#x)!\n", orc, orc));
504 CFRelease(hFlavor);
505 }
506 }
507 else
508 Log(("takePasteboardOwnership: CFStringCreateWithCString failed!\n"));
509 CFRelease(hData);
510 }
511 else
512 Log(("takePasteboardOwnership: CFDataCreate failed!\n"));
513 }
514 else
515 Log(("takePasteboardOwnership: PasteboardClear failed -> %d (%#x)\n", orc, orc));
516 return orc == 0 ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
517}
518
519/**
520 * Write clipboard content to the host clipboard from the internal clipboard
521 * structure.
522 *
523 * @param hPasteboard Reference to the global pasteboard.
524 * @param idOwnership The ownership ID.
525 * @param pv The source buffer.
526 * @param cb The size of the source buffer.
527 * @param fFormat The format type which should be written.
528 *
529 * @returns IPRT status code.
530 */
531int writeToPasteboard(PasteboardRef hPasteboard, uint64_t idOwnership, const void *pv, uint32_t cb, uint32_t fFormat)
532{
533 int rc;
534 OSStatus orc;
535 CFDataRef hData;
536 Log(("writeToPasteboard: fFormat=%#x\n", fFormat));
537
538 /* Make sure all is in sync */
539 PasteboardSynchronize(hPasteboard);
540
541 /*
542 * Handle the unicode text
543 */
544 if (fFormat & VBOX_SHCL_FMT_UNICODETEXT)
545 {
546 PCRTUTF16 const pwszSrc = (PCRTUTF16)pv;
547 size_t const cwcSrc = cb / sizeof(RTUTF16);
548
549 /*
550 * If the other side is windows or OS/2, we may have to convert
551 * '\r\n' -> '\n' and the drop ending marker.
552 */
553
554 /* How long will the converted text be? */
555 size_t cwcDst = 0;
556 rc = ShClUtf16GetLinSize(pwszSrc, cwcSrc, &cwcDst);
557 AssertMsgRCReturn(rc, ("ShClUtf16GetLinSize failed: %Rrc\n", rc), rc);
558
559 /* Ignore empty strings? */
560 if (cwcDst == 0)
561 {
562 Log(("writeToPasteboard: received empty string from the guest; ignoreing it.\n"));
563 return VINF_SUCCESS;
564 }
565
566 /* Allocate the necessary memory and do the conversion. */
567 PRTUTF16 pwszDst = (PRTUTF16)RTMemAlloc(cwcDst * sizeof(RTUTF16));
568 AssertMsgReturn(pwszDst, ("cwcDst=%#zx\n", cwcDst), VERR_NO_UTF16_MEMORY);
569
570 rc = ShClUtf16WinToLin(pwszSrc, cwcSrc, pwszDst, cwcDst);
571 if (RT_SUCCESS(rc))
572 {
573 /*
574 * Create an immutable CFData object that we can place on the clipboard.
575 */
576 hData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)pwszDst, cwcDst * sizeof(RTUTF16));
577 if (hData)
578 {
579 orc = PasteboardPutItemFlavor(hPasteboard, (PasteboardItemID)idOwnership,
580 kUTTypeUTF16PlainText, hData, kPasteboardFlavorNoFlags);
581 if (orc == 0)
582 rc = VINF_SUCCESS;
583 else
584 {
585 Log(("writeToPasteboard: PasteboardPutItemFlavor/kUTTypeUTF16PlainText failed: %d (%#x)\n", orc, orc));
586 rc = VERR_GENERAL_FAILURE;
587 }
588 CFRelease(hData);
589 }
590 else
591 {
592 Log(("writeToPasteboard: CFDataCreate/UTF16 failed!\n"));
593 rc = VERR_NO_MEMORY;
594 }
595
596 /*
597 * Now for the UTF-8 version.
598 */
599 char *pszDst;
600 int rc2 = RTUtf16ToUtf8(pwszDst, &pszDst);
601 if (RT_SUCCESS(rc2))
602 {
603 hData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)pszDst, strlen(pszDst));
604 if (hData)
605 {
606 orc = PasteboardPutItemFlavor(hPasteboard, (PasteboardItemID)idOwnership,
607 kUTTypeUTF8PlainText, hData, kPasteboardFlavorNoFlags);
608 if (orc != 0)
609 {
610 Log(("writeToPasteboard: PasteboardPutItemFlavor/kUTTypeUTF8PlainText failed: %d (%#x)\n", orc, orc));
611 rc = VERR_GENERAL_FAILURE;
612 }
613 CFRelease(hData);
614 }
615 else
616 {
617 Log(("writeToPasteboard: CFDataCreate/UTF8 failed!\n"));
618 rc = VERR_NO_MEMORY;
619 }
620 RTStrFree(pszDst);
621 }
622 else
623 rc = rc2;
624 }
625 else
626 Log(("writeToPasteboard: clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc));
627
628 RTMemFree(pwszDst);
629 }
630 /*
631 * Handle the bitmap. We convert the DIB to a bitmap and put it on
632 * the pasteboard using the BMP flavor.
633 */
634 else if (fFormat & VBOX_SHCL_FMT_BITMAP)
635 {
636 /* Create a full BMP from it */
637 void *pvBmp;
638 size_t cbBmp;
639 rc = ShClDibToBmp(pv, cb, &pvBmp, &cbBmp);
640 if (RT_SUCCESS(rc))
641 {
642 hData = CFDataCreate(kCFAllocatorDefault, (UInt8 const *)pvBmp, cbBmp);
643 if (hData)
644 {
645 orc = PasteboardPutItemFlavor(hPasteboard, (PasteboardItemID)idOwnership,
646 kUTTypeBMP, hData, kPasteboardFlavorNoFlags);
647 if (orc != 0)
648 {
649 Log(("writeToPasteboard: PasteboardPutItemFlavor/kUTTypeBMP failed: %d (%#x)\n", orc, orc));
650 rc = VERR_GENERAL_FAILURE;
651 }
652 CFRelease(hData);
653 }
654 else
655 {
656 Log(("writeToPasteboard: CFDataCreate/UTF8 failed!\n"));
657 rc = VERR_NO_MEMORY;
658 }
659 RTMemFree(pvBmp);
660 }
661 }
662#ifdef WITH_HTML_G2H
663 /*
664 * Handle HTML. Expect UTF-8, ignore line endings and just put it
665 * straigh up on the pasteboard for now.
666 */
667 else if (fFormat & VBOX_SHCL_FMT_HTML)
668 {
669 const char *pszSrc = (const char *)pv;
670 size_t const cchSrc = RTStrNLen(pszSrc, cb);
671 rc = RTStrValidateEncodingEx(pszSrc, cchSrc, 0);
672 if (RT_SUCCESS(rc))
673 {
674 hData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)pszSrc, cchSrc);
675 if (hData)
676 {
677 orc = PasteboardPutItemFlavor(hPasteboard, (PasteboardItemID)idOwnership, kUTTypeHTML,
678 hData, kPasteboardFlavorNoFlags);
679 if (orc == 0)
680 rc = VINF_SUCCESS;
681 else
682 {
683 Log(("writeToPasteboard: PasteboardPutItemFlavor/kUTTypeHTML failed: %d (%#x)\n", orc, orc));
684 rc = VERR_GENERAL_FAILURE;
685 }
686 CFRelease(hData);
687 }
688 else
689 {
690 Log(("writeToPasteboard: CFDataCreate/HTML failed!\n"));
691 rc = VERR_NO_MEMORY;
692 }
693 }
694 else
695 Log(("writeToPasteboard: HTML: Invalid UTF-8 encoding: %Rrc\n", rc));
696 }
697#endif
698 else
699 rc = VERR_NOT_IMPLEMENTED;
700
701 Log(("writeToPasteboard: rc=%Rrc\n", rc));
702 return rc;
703}
704
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