VirtualBox

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

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

OS X host: shared clipboard service: fix potential SEGFAULT when working with UTF16 content.

  • Property eol-style set to native
  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 13.9 KB
Line 
1/* $Id: darwin-pasteboard.cpp 48714 2013-09-26 14:32:14Z 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 pBytePtr = (PRTUTF16)CFDataGetBytePtr(outData);
178 if (pBytePtr)
179 rc = RTUtf16DupEx(&pwszTmp, pBytePtr, 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 rc = RTStrToUtf16((const char*)CFDataGetBytePtr(outData), &pwszTmp);
189 }
190 if (pwszTmp)
191 {
192 /* Check how much longer will the converted text will be. */
193 size_t cwSrc = RTUtf16Len(pwszTmp);
194 size_t cwDest;
195 rc = vboxClipboardUtf16GetWinSize(pwszTmp, cwSrc, &cwDest);
196 if (RT_FAILURE(rc))
197 {
198 RTUtf16Free(pwszTmp);
199 Log(("readFromPasteboard: clipboard conversion failed. vboxClipboardUtf16GetWinSize returned %Rrc. Abandoning.\n", rc));
200 AssertRCReturn(rc, rc);
201 }
202 /* Set the actually needed data size */
203 *pcbActual = cwDest * 2;
204 /* Return success state */
205 rc = VINF_SUCCESS;
206 /* Do not copy data if the dst buffer is not big enough. */
207 if (*pcbActual <= cb)
208 {
209 rc = vboxClipboardUtf16LinToWin(pwszTmp, RTUtf16Len(pwszTmp), static_cast <PRTUTF16>(pv), cb / 2);
210 if (RT_FAILURE(rc))
211 {
212 RTUtf16Free(pwszTmp);
213 Log(("readFromPasteboard: clipboard conversion failed. vboxClipboardUtf16LinToWin() returned %Rrc. Abandoning.\n", rc));
214 AssertRCReturn(rc, rc);
215 }
216#ifdef SHOW_CLIPBOARD_CONTENT
217 Log(("readFromPasteboard: clipboard content: %ls\n", static_cast <PRTUTF16>(pv)));
218#endif
219 }
220 /* Free the temp string */
221 RTUtf16Free(pwszTmp);
222 }
223 }
224 /* The guest request BITMAP */
225 else if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
226 {
227 CFDataRef outData;
228 const void *pTmp = NULL;
229 size_t cbTmpSize;
230 /* Get the data from the pasteboard */
231 if (!(err = PasteboardCopyItemFlavorData(pPasteboard, itemID, kUTTypeBMP, &outData)))
232 {
233 Log(("Clipboard content is BMP\n"));
234 pTmp = CFDataGetBytePtr(outData);
235 cbTmpSize = CFDataGetLength(outData);
236 }
237 if (pTmp)
238 {
239 const void *pDib;
240 size_t cbDibSize;
241 rc = vboxClipboardBmpGetDib(pTmp, cbTmpSize, &pDib, &cbDibSize);
242 if (RT_FAILURE(rc))
243 {
244 rc = VERR_NOT_SUPPORTED;
245 Log(("readFromPasteboard: unknown bitmap format. vboxClipboardBmpGetDib returned %Rrc. Abandoning.\n", rc));
246 AssertRCReturn(rc, rc);
247 }
248
249 *pcbActual = cbDibSize;
250 /* Return success state */
251 rc = VINF_SUCCESS;
252 /* Do not copy data if the dst buffer is not big enough. */
253 if (*pcbActual <= cb)
254 {
255 memcpy(pv, pDib, cbDibSize);
256#ifdef SHOW_CLIPBOARD_CONTENT
257 Log(("readFromPasteboard: clipboard content bitmap %d bytes\n", cbDibSize));
258#endif
259 }
260 }
261 }
262 }
263
264 Log(("readFromPasteboard: rc = %02X\n", rc));
265 return rc;
266}
267
268/**
269 * Write clipboard content to the host clipboard from the internal clipboard
270 * structure.
271 *
272 * @param pPasteboardRef Reference to the global pasteboard.
273 * @param pv The source buffer.
274 * @param cb The size of the source buffer.
275 * @param fFormats The format type which should be written.
276 *
277 * @returns IPRT status code.
278 */
279int writeToPasteboard(PasteboardRef pPasteboard, void *pv, uint32_t cb, uint32_t fFormat)
280{
281 Log(("writeToPasteboard: fFormat = %02X\n", fFormat));
282
283 /* Clear the pasteboard */
284 if (PasteboardClear(pPasteboard))
285 return VERR_NOT_SUPPORTED;
286
287 /* Make sure all is in sync */
288 PasteboardSynchronize(pPasteboard);
289
290 int rc = VERR_NOT_SUPPORTED;
291 /* Handle the unicode text */
292 if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
293 {
294 PRTUTF16 pwszSrcText = static_cast <PRTUTF16>(pv);
295 size_t cwSrc = cb / 2;
296 size_t cwDest = 0;
297 /* How long will the converted text be? */
298 rc = vboxClipboardUtf16GetLinSize(pwszSrcText, cwSrc, &cwDest);
299 if (RT_FAILURE(rc))
300 {
301 Log(("writeToPasteboard: clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc));
302 AssertRCReturn(rc, rc);
303 }
304 /* Empty clipboard? Not critical */
305 if (cwDest == 0)
306 {
307 Log(("writeToPasteboard: received empty clipboard data from the guest, returning false.\n"));
308 return VINF_SUCCESS;
309 }
310 /* Allocate the necessary memory */
311 PRTUTF16 pwszDestText = static_cast <PRTUTF16>(RTMemAlloc(cwDest * 2));
312 if (pwszDestText == NULL)
313 {
314 Log(("writeToPasteboard: failed to allocate %d bytes\n", cwDest * 2));
315 return VERR_NO_MEMORY;
316 }
317 /* Convert the EOL */
318 rc = vboxClipboardUtf16WinToLin(pwszSrcText, cwSrc, pwszDestText, cwDest);
319 if (RT_FAILURE(rc))
320 {
321 Log(("writeToPasteboard: clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc));
322 RTMemFree(pwszDestText);
323 AssertRCReturn(rc, rc);
324 }
325
326 CFDataRef textData = NULL;
327 /* Item id is 1. Nothing special here. */
328 PasteboardItemID itemId = (PasteboardItemID)1;
329 /* Create a CData object which we could pass to the pasteboard */
330 if ((textData = CFDataCreate(kCFAllocatorDefault,
331 reinterpret_cast<UInt8*>(pwszDestText), cwDest * 2)))
332 {
333 /* Put the Utf-16 version to the pasteboard */
334 PasteboardPutItemFlavor(pPasteboard, itemId,
335 kUTTypeUTF16PlainText,
336 textData, 0);
337 }
338 /* Create a Utf-8 version */
339 char *pszDestText;
340 rc = RTUtf16ToUtf8(pwszDestText, &pszDestText);
341 if (RT_SUCCESS(rc))
342 {
343 /* Create a CData object which we could pass to the pasteboard */
344 if ((textData = CFDataCreate(kCFAllocatorDefault,
345 reinterpret_cast<UInt8*>(pszDestText), strlen(pszDestText))))
346 {
347 /* Put the Utf-8 version to the pasteboard */
348 PasteboardPutItemFlavor(pPasteboard, itemId,
349 kUTTypeUTF8PlainText,
350 textData, 0);
351 }
352 RTStrFree(pszDestText);
353 }
354
355 RTMemFree(pwszDestText);
356 rc = VINF_SUCCESS;
357 }
358 /* Handle the bitmap */
359 else if (fFormat & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
360 {
361 /* Create a full BMP from it */
362 void *pBmp;
363 size_t cbBmpSize;
364 CFDataRef bmpData = NULL;
365 /* Item id is 1. Nothing special here. */
366 PasteboardItemID itemId = (PasteboardItemID)1;
367
368 rc = vboxClipboardDibToBmp(pv, cb, &pBmp, &cbBmpSize);
369 if (RT_SUCCESS(rc))
370 {
371 /* Create a CData object which we could pass to the pasteboard */
372 if ((bmpData = CFDataCreate(kCFAllocatorDefault,
373 reinterpret_cast<UInt8*>(pBmp), cbBmpSize)))
374 {
375 /* Put the Utf-8 version to the pasteboard */
376 PasteboardPutItemFlavor(pPasteboard, itemId,
377 kUTTypeBMP,
378 bmpData, 0);
379 }
380 RTMemFree(pBmp);
381 }
382 rc = VINF_SUCCESS;
383 }
384 else
385 rc = VERR_NOT_IMPLEMENTED;
386
387 Log(("writeToPasteboard: rc = %02X\n", rc));
388 return rc;
389}
390
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