VirtualBox

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

Last change on this file since 61361 was 48717, checked in by vboxsync, 11 years ago

OS X host: shared clipboard service: fix potential SEGFAULT when working with UTF16 content: updated coding style, treat more carefully with UTF8 content as well.

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