VirtualBox

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

Last change on this file since 75969 was 75506, checked in by vboxsync, 6 years ago

Make scm happy.

  • Property eol-style set to native
  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 14.9 KB
Line 
1/* $Id: darwin-pasteboard.cpp 75506 2018-11-16 02:38:27Z 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-2017 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/mem.h>
28#include <iprt/assert.h>
29#include "iprt/err.h"
30
31#include "VBox/log.h"
32#include "VBox/HostServices/VBoxClipboardSvc.h"
33#include "VBox/GuestHost/clipboard-helper.h"
34
35
36/*********************************************************************************************************************************
37* Defined Constants And Macros *
38*********************************************************************************************************************************/
39/* For debugging */
40//#define SHOW_CLIPBOARD_CONTENT
41
42
43/**
44 * Initialize the global pasteboard and return a reference to it.
45 *
46 * @param pPasteboardRef Reference to the global pasteboard.
47 *
48 * @returns IPRT status code.
49 */
50int initPasteboard(PasteboardRef *pPasteboardRef)
51{
52 int rc = VINF_SUCCESS;
53
54 if (PasteboardCreate(kPasteboardClipboard, pPasteboardRef))
55 rc = VERR_NOT_SUPPORTED;
56
57 return rc;
58}
59
60/**
61 * Release the reference to the global pasteboard.
62 *
63 * @param pPasteboardRef Reference to the global pasteboard.
64 */
65void destroyPasteboard(PasteboardRef *pPasteboardRef)
66{
67 CFRelease(*pPasteboardRef);
68 *pPasteboardRef = NULL;
69}
70
71/**
72 * Inspect the global pasteboard for new content. Check if there is some type
73 * that is supported by vbox and return it.
74 *
75 * @param pPasteboard Reference to the global pasteboard.
76 * @param pfFormats Pointer for the bit combination of the
77 * supported types.
78 * @param pfChanged True if something has changed after the
79 * last call.
80 *
81 * @returns IPRT status code. (Always VINF_SUCCESS atm.)
82 */
83int queryNewPasteboardFormats(PasteboardRef pPasteboard, uint32_t *pfFormats, bool *pfChanged)
84{
85 Log(("queryNewPasteboardFormats\n"));
86
87 OSStatus err = noErr;
88 *pfChanged = true;
89
90 PasteboardSyncFlags syncFlags;
91 /* Make sure all is in sync */
92 syncFlags = PasteboardSynchronize(pPasteboard);
93 /* If nothing changed return */
94 if (!(syncFlags & kPasteboardModified))
95 {
96 *pfChanged = false;
97 return VINF_SUCCESS;
98 }
99
100 /* Are some items in the pasteboard? */
101 ItemCount itemCount;
102 err = PasteboardGetItemCount(pPasteboard, &itemCount);
103 if (itemCount < 1)
104 return VINF_SUCCESS;
105
106 /* The id of the first element in the pasteboard */
107 int rc = VINF_SUCCESS;
108 PasteboardItemID itemID;
109 if (!(err = PasteboardGetItemIdentifier(pPasteboard, 1, &itemID)))
110 {
111 /* Retrieve all flavors in the pasteboard, maybe there
112 * is something we can use. */
113 CFArrayRef flavorTypeArray;
114 if (!(err = PasteboardCopyItemFlavors(pPasteboard, itemID, &flavorTypeArray)))
115 {
116 CFIndex flavorCount;
117 flavorCount = CFArrayGetCount(flavorTypeArray);
118 for (CFIndex flavorIndex = 0; flavorIndex < flavorCount; flavorIndex++)
119 {
120 CFStringRef flavorType;
121 flavorType = static_cast <CFStringRef>(CFArrayGetValueAtIndex(flavorTypeArray,
122 flavorIndex));
123 /* Currently only unicode supported */
124 if (UTTypeConformsTo(flavorType, kUTTypeUTF8PlainText) ||
125 UTTypeConformsTo(flavorType, kUTTypeUTF16PlainText))
126 {
127 Log(("Unicode flavor detected.\n"));
128 *pfFormats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
129 }
130 else if (UTTypeConformsTo(flavorType, kUTTypeBMP))
131 {
132 Log(("BMP flavor detected.\n"));
133 *pfFormats |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
134 }
135 }
136 CFRelease(flavorTypeArray);
137 }
138 }
139
140 Log(("queryNewPasteboardFormats: rc = %02X\n", rc));
141 return rc;
142}
143
144/**
145 * Read content from the host clipboard and write it to the internal clipboard
146 * structure for further processing.
147 *
148 * @param pPasteboard Reference to the global pasteboard.
149 * @param fFormat The format type which should be read.
150 * @param pv The destination buffer.
151 * @param cb The size of the destination buffer.
152 * @param pcbActual The size which is needed to transfer the content.
153 *
154 * @returns IPRT status code.
155 */
156int readFromPasteboard(PasteboardRef pPasteboard, uint32_t fFormat, void *pv, uint32_t cb, uint32_t *pcbActual)
157{
158 Log(("readFromPasteboard: fFormat = %02X\n", fFormat));
159
160 OSStatus err = noErr;
161
162 /* Make sure all is in sync */
163 PasteboardSynchronize(pPasteboard);
164
165 /* Are some items in the pasteboard? */
166 ItemCount itemCount;
167 err = PasteboardGetItemCount(pPasteboard, &itemCount);
168 if (itemCount < 1)
169 return VINF_SUCCESS;
170
171 /* The id of the first element in the pasteboard */
172 int rc = VERR_NOT_SUPPORTED;
173 PasteboardItemID itemID;
174 if (!(err = PasteboardGetItemIdentifier(pPasteboard, 1, &itemID)))
175 {
176 /* The guest request unicode */
177 if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
178 {
179 CFDataRef outData;
180 PRTUTF16 pwszTmp = NULL;
181 /* Try utf-16 first */
182 if (!(err = PasteboardCopyItemFlavorData(pPasteboard, itemID, kUTTypeUTF16PlainText, &outData)))
183 {
184 Log(("Clipboard content is utf-16\n"));
185
186 PRTUTF16 pwszString = (PRTUTF16)CFDataGetBytePtr(outData);
187 if (pwszString)
188 rc = RTUtf16DupEx(&pwszTmp, pwszString, 0);
189 else
190 rc = VERR_INVALID_PARAMETER;
191 }
192 /* Second try is utf-8 */
193 else
194 if (!(err = PasteboardCopyItemFlavorData(pPasteboard, itemID, kUTTypeUTF8PlainText, &outData)))
195 {
196 Log(("readFromPasteboard: clipboard content is utf-8\n"));
197 const char *pszString = (const char *)CFDataGetBytePtr(outData);
198 if (pszString)
199 rc = RTStrToUtf16(pszString, &pwszTmp);
200 else
201 rc = VERR_INVALID_PARAMETER;
202 }
203 if (pwszTmp)
204 {
205 /* Check how much longer will the converted text will be. */
206 size_t cwSrc = RTUtf16Len(pwszTmp);
207 size_t cwDest;
208 rc = vboxClipboardUtf16GetWinSize(pwszTmp, cwSrc, &cwDest);
209 if (RT_FAILURE(rc))
210 {
211 RTUtf16Free(pwszTmp);
212 Log(("readFromPasteboard: clipboard conversion failed. vboxClipboardUtf16GetWinSize returned %Rrc. Abandoning.\n", rc));
213 AssertRCReturn(rc, rc);
214 }
215 /* Set the actually needed data size */
216 *pcbActual = cwDest * 2;
217 /* Return success state */
218 rc = VINF_SUCCESS;
219 /* Do not copy data if the dst buffer is not big enough. */
220 if (*pcbActual <= cb)
221 {
222 rc = vboxClipboardUtf16LinToWin(pwszTmp, RTUtf16Len(pwszTmp), static_cast <PRTUTF16>(pv), cb / 2);
223 if (RT_FAILURE(rc))
224 {
225 RTUtf16Free(pwszTmp);
226 Log(("readFromPasteboard: clipboard conversion failed. vboxClipboardUtf16LinToWin() returned %Rrc. Abandoning.\n", rc));
227 AssertRCReturn(rc, rc);
228 }
229#ifdef SHOW_CLIPBOARD_CONTENT
230 Log(("readFromPasteboard: clipboard content: %ls\n", static_cast <PRTUTF16>(pv)));
231#endif
232 }
233 /* Free the temp string */
234 RTUtf16Free(pwszTmp);
235 }
236 }
237 /* The guest request BITMAP */
238 else if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
239 {
240 CFDataRef outData;
241 const void *pTmp = NULL;
242 size_t cbTmpSize;
243 /* Get the data from the pasteboard */
244 if (!(err = PasteboardCopyItemFlavorData(pPasteboard, itemID, kUTTypeBMP, &outData)))
245 {
246 Log(("Clipboard content is BMP\n"));
247 pTmp = CFDataGetBytePtr(outData);
248 cbTmpSize = CFDataGetLength(outData);
249 }
250 if (pTmp)
251 {
252 const void *pDib;
253 size_t cbDibSize;
254 rc = vboxClipboardBmpGetDib(pTmp, cbTmpSize, &pDib, &cbDibSize);
255 if (RT_FAILURE(rc))
256 {
257 rc = VERR_NOT_SUPPORTED;
258 Log(("readFromPasteboard: unknown bitmap format. vboxClipboardBmpGetDib returned %Rrc. Abandoning.\n", rc));
259 AssertRCReturn(rc, rc);
260 }
261
262 *pcbActual = cbDibSize;
263 /* Return success state */
264 rc = VINF_SUCCESS;
265 /* Do not copy data if the dst buffer is not big enough. */
266 if (*pcbActual <= cb)
267 {
268 memcpy(pv, pDib, cbDibSize);
269#ifdef SHOW_CLIPBOARD_CONTENT
270 Log(("readFromPasteboard: clipboard content bitmap %d bytes\n", cbDibSize));
271#endif
272 }
273 }
274 }
275 }
276
277 Log(("readFromPasteboard: rc = %02X\n", rc));
278 return rc;
279}
280
281/**
282 * Write clipboard content to the host clipboard from the internal clipboard
283 * structure.
284 *
285 * @param pPasteboard Reference to the global pasteboard.
286 * @param pv The source buffer.
287 * @param cb The size of the source buffer.
288 * @param fFormat The format type which should be written.
289 *
290 * @returns IPRT status code.
291 */
292int writeToPasteboard(PasteboardRef pPasteboard, void *pv, uint32_t cb, uint32_t fFormat)
293{
294 Log(("writeToPasteboard: fFormat = %02X\n", fFormat));
295
296 /* Clear the pasteboard */
297 if (PasteboardClear(pPasteboard))
298 return VERR_NOT_SUPPORTED;
299
300 /* Make sure all is in sync */
301 PasteboardSynchronize(pPasteboard);
302
303 int rc = VERR_NOT_SUPPORTED;
304 /* Handle the unicode text */
305 if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
306 {
307 PRTUTF16 pwszSrcText = static_cast <PRTUTF16>(pv);
308 size_t cwSrc = cb / 2;
309 size_t cwDest = 0;
310 /* How long will the converted text be? */
311 rc = vboxClipboardUtf16GetLinSize(pwszSrcText, cwSrc, &cwDest);
312 if (RT_FAILURE(rc))
313 {
314 Log(("writeToPasteboard: clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));
315 AssertRCReturn(rc, rc);
316 }
317 /* Empty clipboard? Not critical */
318 if (cwDest == 0)
319 {
320 Log(("writeToPasteboard: received empty clipboard data from the guest, returning false.\n"));
321 return VINF_SUCCESS;
322 }
323 /* Allocate the necessary memory */
324 PRTUTF16 pwszDestText = static_cast <PRTUTF16>(RTMemAlloc(cwDest * 2));
325 if (pwszDestText == NULL)
326 {
327 Log(("writeToPasteboard: failed to allocate %d bytes\n", cwDest * 2));
328 return VERR_NO_MEMORY;
329 }
330 /* Convert the EOL */
331 rc = vboxClipboardUtf16WinToLin(pwszSrcText, cwSrc, pwszDestText, cwDest);
332 if (RT_FAILURE(rc))
333 {
334 Log(("writeToPasteboard: clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc));
335 RTMemFree(pwszDestText);
336 AssertRCReturn(rc, rc);
337 }
338
339 CFDataRef textData = NULL;
340 /* Item id is 1. Nothing special here. */
341 PasteboardItemID itemId = (PasteboardItemID)1;
342 /* Create a CData object which we could pass to the pasteboard */
343 if ((textData = CFDataCreate(kCFAllocatorDefault,
344 reinterpret_cast<UInt8*>(pwszDestText), cwDest * 2)))
345 {
346 /* Put the Utf-16 version to the pasteboard */
347 PasteboardPutItemFlavor(pPasteboard, itemId,
348 kUTTypeUTF16PlainText,
349 textData, 0);
350 }
351 /* Create a Utf-8 version */
352 char *pszDestText;
353 rc = RTUtf16ToUtf8(pwszDestText, &pszDestText);
354 if (RT_SUCCESS(rc))
355 {
356 /* Create a CData object which we could pass to the pasteboard */
357 if ((textData = CFDataCreate(kCFAllocatorDefault,
358 reinterpret_cast<UInt8*>(pszDestText), strlen(pszDestText))))
359 {
360 /* Put the Utf-8 version to the pasteboard */
361 PasteboardPutItemFlavor(pPasteboard, itemId,
362 kUTTypeUTF8PlainText,
363 textData, 0);
364 }
365 RTStrFree(pszDestText);
366 }
367
368 RTMemFree(pwszDestText);
369 rc = VINF_SUCCESS;
370 }
371 /* Handle the bitmap */
372 else if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
373 {
374 /* Create a full BMP from it */
375 void *pBmp;
376 size_t cbBmpSize;
377 CFDataRef bmpData = NULL;
378 /* Item id is 1. Nothing special here. */
379 PasteboardItemID itemId = (PasteboardItemID)1;
380
381 rc = vboxClipboardDibToBmp(pv, cb, &pBmp, &cbBmpSize);
382 if (RT_SUCCESS(rc))
383 {
384 /* Create a CData object which we could pass to the pasteboard */
385 if ((bmpData = CFDataCreate(kCFAllocatorDefault,
386 reinterpret_cast<UInt8*>(pBmp), cbBmpSize)))
387 {
388 /* Put the Utf-8 version to the pasteboard */
389 PasteboardPutItemFlavor(pPasteboard, itemId,
390 kUTTypeBMP,
391 bmpData, 0);
392 }
393 RTMemFree(pBmp);
394 }
395 rc = VINF_SUCCESS;
396 }
397 else
398 rc = VERR_NOT_IMPLEMENTED;
399
400 Log(("writeToPasteboard: rc = %02X\n", rc));
401 return rc;
402}
403
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