VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp@ 79036

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

Shared Clipboard/URI: Update.

  • Property eol-style set to native
  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 33.0 KB
Line 
1/* $Id: clipboard-common.cpp 79036 2019-06-07 14:56:19Z vboxsync $ */
2/** @file
3 * Shared Clipboard: Some helper function for converting between the various eol.
4 */
5
6/*
7 * Includes contributions from François Revol
8 *
9 * Copyright (C) 2006-2019 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_SHARED_CLIPBOARD
21
22#include <iprt/alloc.h>
23#include <iprt/assert.h>
24#include <iprt/errcore.h>
25
26#include <VBox/log.h>
27#include <VBox/GuestHost/clipboard-helper.h>
28#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
29# include <VBox/GuestHost/SharedClipboard-uri.h>
30#endif
31
32
33#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
34static int sharedClipboardURITransferThreadCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer);
35static int sharedClipboardURITransferThreadDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer, RTMSINTERVAL uTimeoutMs);
36static int sharedClipboardURITransferReadThread(RTTHREAD hThread, void *pvUser);
37static int sharedClipboardURITransferWriteThread(RTTHREAD hThread, void *pvUser);
38static PSHAREDCLIPBOARDURITRANSFER sharedClipboardURICtxGetTransferInternal(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx);
39#endif
40
41
42/** @todo use const where appropriate; delinuxify the code (*Lin* -> *Host*); use AssertLogRel*. */
43
44int vboxClipboardUtf16GetWinSize(PRTUTF16 pwszSrc, size_t cwSrc, size_t *pcwDest)
45{
46 size_t cwDest, i;
47
48 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
49 AssertLogRelMsgReturn(pwszSrc != NULL, ("vboxClipboardUtf16GetWinSize: received a null Utf16 string, returning VERR_INVALID_PARAMETER\n"), VERR_INVALID_PARAMETER);
50 if (cwSrc == 0)
51 {
52 *pcwDest = 0;
53 LogFlowFunc(("empty source string, returning\n"));
54 return VINF_SUCCESS;
55 }
56/** @todo convert the remainder of the Assert stuff to AssertLogRel. */
57 /* We only take little endian Utf16 */
58 if (pwszSrc[0] == UTF16BEMARKER)
59 {
60 LogRel(("vboxClipboardUtf16GetWinSize: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
61 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
62 }
63 cwDest = 0;
64 /* Calculate the size of the destination text string. */
65 /* Is this Utf16 or Utf16-LE? */
66 for (i = (pwszSrc[0] == UTF16LEMARKER ? 1 : 0); i < cwSrc; ++i, ++cwDest)
67 {
68 /* Check for a single line feed */
69 if (pwszSrc[i] == LINEFEED)
70 ++cwDest;
71#ifdef RT_OS_DARWIN
72 /* Check for a single carriage return (MacOS) */
73 if (pwszSrc[i] == CARRIAGERETURN)
74 ++cwDest;
75#endif
76 if (pwszSrc[i] == 0)
77 {
78 /* Don't count this, as we do so below. */
79 break;
80 }
81 }
82 /* Count the terminating null byte. */
83 ++cwDest;
84 LogFlowFunc(("returning VINF_SUCCESS, %d 16bit words\n", cwDest));
85 *pcwDest = cwDest;
86 return VINF_SUCCESS;
87}
88
89int vboxClipboardUtf16LinToWin(PRTUTF16 pwszSrc, size_t cwSrc, PRTUTF16 pu16Dest,
90 size_t cwDest)
91{
92 size_t i, j;
93 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
94 if (!VALID_PTR(pwszSrc) || !VALID_PTR(pu16Dest))
95 {
96 LogRel(("vboxClipboardUtf16LinToWin: received an invalid pointer, pwszSrc=%p, pu16Dest=%p, returning VERR_INVALID_PARAMETER\n", pwszSrc, pu16Dest));
97 AssertReturn(VALID_PTR(pwszSrc) && VALID_PTR(pu16Dest), VERR_INVALID_PARAMETER);
98 }
99 if (cwSrc == 0)
100 {
101 if (cwDest == 0)
102 {
103 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
104 return VERR_BUFFER_OVERFLOW;
105 }
106 pu16Dest[0] = 0;
107 LogFlowFunc(("empty source string, returning\n"));
108 return VINF_SUCCESS;
109 }
110 /* We only take little endian Utf16 */
111 if (pwszSrc[0] == UTF16BEMARKER)
112 {
113 LogRel(("vboxClipboardUtf16LinToWin: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
114 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
115 }
116 /* Don't copy the endian marker. */
117 for (i = (pwszSrc[0] == UTF16LEMARKER ? 1 : 0), j = 0; i < cwSrc; ++i, ++j)
118 {
119 /* Don't copy the null byte, as we add it below. */
120 if (pwszSrc[i] == 0)
121 break;
122 if (j == cwDest)
123 {
124 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
125 return VERR_BUFFER_OVERFLOW;
126 }
127 if (pwszSrc[i] == LINEFEED)
128 {
129 pu16Dest[j] = CARRIAGERETURN;
130 ++j;
131 if (j == cwDest)
132 {
133 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
134 return VERR_BUFFER_OVERFLOW;
135 }
136 }
137#ifdef RT_OS_DARWIN
138 /* Check for a single carriage return (MacOS) */
139 else if (pwszSrc[i] == CARRIAGERETURN)
140 {
141 /* set cr */
142 pu16Dest[j] = CARRIAGERETURN;
143 ++j;
144 if (j == cwDest)
145 {
146 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
147 return VERR_BUFFER_OVERFLOW;
148 }
149 /* add the lf */
150 pu16Dest[j] = LINEFEED;
151 continue;
152 }
153#endif
154 pu16Dest[j] = pwszSrc[i];
155 }
156 /* Add the trailing null. */
157 if (j == cwDest)
158 {
159 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
160 return VERR_BUFFER_OVERFLOW;
161 }
162 pu16Dest[j] = 0;
163 LogFlowFunc(("rc=VINF_SUCCESS, pu16Dest=%ls\n", pu16Dest));
164 return VINF_SUCCESS;
165}
166
167int vboxClipboardUtf16GetLinSize(PRTUTF16 pwszSrc, size_t cwSrc, size_t *pcwDest)
168{
169 size_t cwDest;
170
171 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
172 if (!VALID_PTR(pwszSrc))
173 {
174 LogRel(("vboxClipboardUtf16GetLinSize: received an invalid Utf16 string %p. Returning VERR_INVALID_PARAMETER.\n", pwszSrc));
175 AssertReturn(VALID_PTR(pwszSrc), VERR_INVALID_PARAMETER);
176 }
177 if (cwSrc == 0)
178 {
179 LogFlowFunc(("empty source string, returning VINF_SUCCESS\n"));
180 *pcwDest = 0;
181 return VINF_SUCCESS;
182 }
183 /* We only take little endian Utf16 */
184 if (pwszSrc[0] == UTF16BEMARKER)
185 {
186 LogRel(("vboxClipboardUtf16GetLinSize: received a big endian Utf16 string. Returning VERR_INVALID_PARAMETER.\n"));
187 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
188 }
189 /* Calculate the size of the destination text string. */
190 /* Is this Utf16 or Utf16-LE? */
191 if (pwszSrc[0] == UTF16LEMARKER)
192 cwDest = 0;
193 else
194 cwDest = 1;
195 for (size_t i = 0; i < cwSrc; ++i, ++cwDest)
196 {
197 if ( (i + 1 < cwSrc)
198 && (pwszSrc[i] == CARRIAGERETURN)
199 && (pwszSrc[i + 1] == LINEFEED))
200 {
201 ++i;
202 }
203 if (pwszSrc[i] == 0)
204 {
205 break;
206 }
207 }
208 /* Terminating zero */
209 ++cwDest;
210 LogFlowFunc(("returning %d\n", cwDest));
211 *pcwDest = cwDest;
212 return VINF_SUCCESS;
213}
214
215int vboxClipboardUtf16WinToLin(PRTUTF16 pwszSrc, size_t cwSrc, PRTUTF16 pu16Dest,
216 size_t cwDest)
217{
218 size_t cwDestPos;
219
220 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u, pu16Dest=%p, cwDest=%u\n",
221 cwSrc, pwszSrc, cwSrc, pu16Dest, cwDest));
222 /* A buffer of size 0 may not be an error, but it is not a good idea either. */
223 Assert(cwDest > 0);
224 if (!VALID_PTR(pwszSrc) || !VALID_PTR(pu16Dest))
225 {
226 LogRel(("vboxClipboardUtf16WinToLin: received an invalid ptr, pwszSrc=%p, pu16Dest=%p, returning VERR_INVALID_PARAMETER\n", pwszSrc, pu16Dest));
227 AssertReturn(VALID_PTR(pwszSrc) && VALID_PTR(pu16Dest), VERR_INVALID_PARAMETER);
228 }
229 /* We only take little endian Utf16 */
230 if (pwszSrc[0] == UTF16BEMARKER)
231 {
232 LogRel(("vboxClipboardUtf16WinToLin: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
233 AssertMsgFailedReturn(("received a big endian string\n"), VERR_INVALID_PARAMETER);
234 }
235 if (cwDest == 0)
236 {
237 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
238 return VERR_BUFFER_OVERFLOW;
239 }
240 if (cwSrc == 0)
241 {
242 pu16Dest[0] = 0;
243 LogFlowFunc(("received empty string. Returning VINF_SUCCESS\n"));
244 return VINF_SUCCESS;
245 }
246 /* Prepend the Utf16 byte order marker if it is missing. */
247 if (pwszSrc[0] == UTF16LEMARKER)
248 {
249 cwDestPos = 0;
250 }
251 else
252 {
253 pu16Dest[0] = UTF16LEMARKER;
254 cwDestPos = 1;
255 }
256 for (size_t i = 0; i < cwSrc; ++i, ++cwDestPos)
257 {
258 if (pwszSrc[i] == 0)
259 {
260 break;
261 }
262 if (cwDestPos == cwDest)
263 {
264 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
265 return VERR_BUFFER_OVERFLOW;
266 }
267 if ( (i + 1 < cwSrc)
268 && (pwszSrc[i] == CARRIAGERETURN)
269 && (pwszSrc[i + 1] == LINEFEED))
270 {
271 ++i;
272 }
273 pu16Dest[cwDestPos] = pwszSrc[i];
274 }
275 /* Terminating zero */
276 if (cwDestPos == cwDest)
277 {
278 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
279 return VERR_BUFFER_OVERFLOW;
280 }
281 pu16Dest[cwDestPos] = 0;
282 LogFlowFunc(("set string %ls. Returning\n", pu16Dest + 1));
283 return VINF_SUCCESS;
284}
285
286int vboxClipboardDibToBmp(const void *pvSrc, size_t cbSrc, void **ppvDest, size_t *pcbDest)
287{
288 size_t cb = sizeof(BMFILEHEADER) + cbSrc;
289 PBMFILEHEADER pFileHeader = NULL;
290 void *pvDest = NULL;
291 size_t offPixel = 0;
292
293 AssertPtrReturn(pvSrc, VERR_INVALID_PARAMETER);
294 AssertPtrReturn(ppvDest, VERR_INVALID_PARAMETER);
295 AssertPtrReturn(pcbDest, VERR_INVALID_PARAMETER);
296
297 PBMINFOHEADER pBitmapInfoHeader = (PBMINFOHEADER)pvSrc;
298 /** @todo Support all the many versions of the DIB headers. */
299 if ( cbSrc < sizeof(BMINFOHEADER)
300 || RT_LE2H_U32(pBitmapInfoHeader->u32Size) < sizeof(BMINFOHEADER)
301 || RT_LE2H_U32(pBitmapInfoHeader->u32Size) != sizeof(BMINFOHEADER))
302 {
303 Log(("vboxClipboardDibToBmp: invalid or unsupported bitmap data.\n"));
304 return VERR_INVALID_PARAMETER;
305 }
306
307 offPixel = sizeof(BMFILEHEADER)
308 + RT_LE2H_U32(pBitmapInfoHeader->u32Size)
309 + RT_LE2H_U32(pBitmapInfoHeader->u32ClrUsed) * sizeof(uint32_t);
310 if (cbSrc < offPixel)
311 {
312 Log(("vboxClipboardDibToBmp: invalid bitmap data.\n"));
313 return VERR_INVALID_PARAMETER;
314 }
315
316 pvDest = RTMemAlloc(cb);
317 if (!pvDest)
318 {
319 Log(("writeToPasteboard: cannot allocate memory for bitmap.\n"));
320 return VERR_NO_MEMORY;
321 }
322
323 pFileHeader = (PBMFILEHEADER)pvDest;
324 pFileHeader->u16Type = BITMAPHEADERMAGIC;
325 pFileHeader->u32Size = (uint32_t)RT_H2LE_U32(cb);
326 pFileHeader->u16Reserved1 = pFileHeader->u16Reserved2 = 0;
327 pFileHeader->u32OffBits = (uint32_t)RT_H2LE_U32(offPixel);
328 memcpy((uint8_t *)pvDest + sizeof(BMFILEHEADER), pvSrc, cbSrc);
329 *ppvDest = pvDest;
330 *pcbDest = cb;
331 return VINF_SUCCESS;
332}
333
334int vboxClipboardBmpGetDib(const void *pvSrc, size_t cbSrc, const void **ppvDest, size_t *pcbDest)
335{
336 AssertPtrReturn(pvSrc, VERR_INVALID_PARAMETER);
337 AssertPtrReturn(ppvDest, VERR_INVALID_PARAMETER);
338 AssertPtrReturn(pcbDest, VERR_INVALID_PARAMETER);
339
340 PBMFILEHEADER pFileHeader = (PBMFILEHEADER)pvSrc;
341 if ( cbSrc < sizeof(BMFILEHEADER)
342 || pFileHeader->u16Type != BITMAPHEADERMAGIC
343 || RT_LE2H_U32(pFileHeader->u32Size) != cbSrc)
344 {
345 Log(("vboxClipboardBmpGetDib: invalid bitmap data.\n"));
346 return VERR_INVALID_PARAMETER;
347 }
348
349 *ppvDest = ((uint8_t *)pvSrc) + sizeof(BMFILEHEADER);
350 *pcbDest = cbSrc - sizeof(BMFILEHEADER);
351 return VINF_SUCCESS;
352}
353
354#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
355/**
356 * Initializes an URI clipboard transfer struct.
357 *
358 * @returns VBox status code.
359 * @param enmDir Transfer direction.
360 * @param pCtx Shared Clipboard provider creation context to use.
361 * @param ppTransfer Where to return the created URI transfer struct.
362 * Must be destroyed by SharedClipboardURITransferDestroy().
363 */
364int SharedClipboardURITransferCreate(SHAREDCLIPBOARDURITRANSFERDIR enmDir, PSHAREDCLIPBOARDPROVIDERCREATIONCTX pCtx,
365 PSHAREDCLIPBOARDURITRANSFER *ppTransfer)
366{
367 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
368 AssertPtrReturn(ppTransfer, VERR_INVALID_POINTER);
369
370 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)RTMemAlloc(sizeof(SHAREDCLIPBOARDURITRANSFER));
371 if (!pTransfer)
372 return VERR_NO_MEMORY;
373
374 LogFlowFuncEnter();
375
376 pTransfer->enmDir = enmDir;
377
378 SharedClipboardMetaDataInit(&pTransfer->Meta);
379
380 pTransfer->pProvider = SharedClipboardProvider::Create(pCtx);
381 if (!pTransfer->pProvider)
382 return VERR_NO_MEMORY;
383
384 pTransfer->Thread.hThread = NIL_RTTHREAD;
385 pTransfer->Thread.fCancelled = false;
386 pTransfer->Thread.fStarted = false;
387
388 pTransfer->pvUser = NULL;
389 pTransfer->cbUser = 0;
390
391 *ppTransfer = pTransfer;
392
393 LogFlowFuncLeave();
394 return VINF_SUCCESS;
395}
396
397/**
398 * Destroys an URI clipboard transfer context struct.
399 *
400 * @returns VBox status code.
401 * @param pURI URI clipboard transfer struct to destroy.
402 */
403int SharedClipboardURITransferDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer)
404{
405 if (!pTransfer)
406 return VINF_SUCCESS;
407
408 LogFlowFuncEnter();
409
410 int rc = sharedClipboardURITransferThreadDestroy(pTransfer, 30 * 1000 /* Timeout in ms */);
411 if (RT_FAILURE(rc))
412 return rc;
413
414 SharedClipboardMetaDataDestroy(&pTransfer->Meta);
415
416 if (pTransfer->pProvider)
417 {
418 delete pTransfer->pProvider;
419 pTransfer->pProvider = NULL;
420 }
421
422 RTMemFree(pTransfer);
423 pTransfer = NULL;
424
425 LogFlowFuncLeave();
426
427 return VINF_SUCCESS;
428}
429
430/**
431 * Resets an clipboard URI transfer.
432 *
433 * @param pTransfer URI clipboard transfer struct to reset.
434 */
435void SharedClipboardURITransferReset(PSHAREDCLIPBOARDURITRANSFER pTransfer)
436{
437 AssertPtrReturnVoid(pTransfer);
438
439 LogFlowFuncEnter();
440
441 /** @todo Anything else to do here? */
442
443 if (pTransfer->pProvider)
444 pTransfer->pProvider->Reset();
445
446 pTransfer->URIList.Clear();
447}
448
449/**
450 * Returns the current URI object for a clipboard URI transfer.
451 *
452 * @returns VBox status code.
453 * @param pTransfer URI clipboard transfer struct to return current URI object for.
454 */
455const SharedClipboardURIObject *SharedClipboardURITransferGetCurrentObject(PSHAREDCLIPBOARDURITRANSFER pTransfer)
456{
457 AssertPtrReturn(pTransfer, NULL);
458
459 return pTransfer->URIList.First();
460}
461
462/**
463 * Returns the provider for a clipboard URI transfer.
464 *
465 * @returns VBox status code.
466 * @param pTransfer URI clipboard transfer struct to return provider for.
467 */
468SharedClipboardProvider *SharedClipboardURITransferGetProvider(PSHAREDCLIPBOARDURITRANSFER pTransfer)
469{
470 AssertPtrReturn(pTransfer, NULL);
471
472 return pTransfer->pProvider;
473}
474
475/**
476 * Returns the URI list for a clipboard URI transfer.
477 *
478 * @returns Pointer to URI list.
479 * @param pTransfer URI clipboard transfer struct to return URI list for.
480 */
481const SharedClipboardURIList *SharedClipboardURITransferGetList(PSHAREDCLIPBOARDURITRANSFER pTransfer)
482{
483 return &pTransfer->URIList;
484}
485
486/**
487 * Returns the current URI object for a clipboard URI transfer.
488 *
489 * @returns Pointer to URI object.
490 * @param pTransfer URI clipboard transfer struct to return URI object for.
491 */
492const SharedClipboardURIObject *SharedClipboardURITransferGetObject(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint64_t uIdx)
493{
494 return pTransfer->URIList.At(uIdx);
495}
496
497int SharedClipboardURITransferRun(PSHAREDCLIPBOARDURITRANSFER pTransfer, bool fAsync)
498{
499 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
500
501 int rc;
502
503 LogFlowFunc(("fAsync=%RTbool\n", fAsync));
504
505 if (fAsync)
506 {
507 rc = sharedClipboardURITransferThreadCreate(pTransfer);
508 }
509 else
510 {
511 if (pTransfer->enmDir == SHAREDCLIPBOARDURITRANSFERDIR_READ)
512 rc = SharedClipboardURITransferRead(pTransfer);
513 else if (pTransfer->enmDir == SHAREDCLIPBOARDURITRANSFERDIR_WRITE)
514 rc = SharedClipboardURITransferWrite(pTransfer);
515 else
516 rc = VERR_NOT_IMPLEMENTED;
517 }
518
519 LogFlowFuncLeaveRC(rc);
520 return rc;
521}
522
523/**
524 * Sets or unsets the callback table to be used for a clipboard URI transfer.
525 *
526 * @returns VBox status code.
527 * @param pTransfer URI clipboard transfer struct to set callbacks for.
528 * @param pCallbacks Pointer to callback table to set. Specify NULL to unset existing callbacks.
529 */
530void SharedClipboardURITransferSetCallbacks(PSHAREDCLIPBOARDURITRANSFER pTransfer, PSHAREDCLIPBOARDURITRANSFERCALLBACKS pCallbacks)
531{
532 AssertPtrReturnVoid(pTransfer);
533 /* pCallbacks might be NULL to unset callbacks. */
534
535 LogFlowFunc(("pCallbacks=%p\n", pCallbacks));
536
537 if (pCallbacks)
538 {
539 pTransfer->Callbacks = *pCallbacks;
540 }
541 else
542 RT_ZERO(pTransfer->Callbacks);
543}
544
545/**
546 * Creates a thread for a clipboard URI transfer.
547 *
548 * @returns VBox status code.
549 * @param pTransfer URI clipboard transfer struct to create thread for.
550 */
551static int sharedClipboardURITransferThreadCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer)
552{
553 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
554
555 PFNRTTHREAD pfnRTThread = NULL;
556
557 if (pTransfer->enmDir == SHAREDCLIPBOARDURITRANSFERDIR_READ)
558 pfnRTThread = sharedClipboardURITransferReadThread;
559 else if (pTransfer->enmDir == SHAREDCLIPBOARDURITRANSFERDIR_WRITE)
560 pfnRTThread = sharedClipboardURITransferWriteThread;
561
562 AssertPtrReturn(pfnRTThread, VERR_NOT_SUPPORTED);
563
564 /* Spawn a worker thread, so that we don't block the window thread for too long. */
565 int rc = RTThreadCreate(&pTransfer->Thread.hThread, pfnRTThread,
566 pTransfer /* pvUser */, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
567 "vbxshclp");
568 if (RT_SUCCESS(rc))
569 {
570 int rc2 = RTThreadUserWait(pTransfer->Thread.hThread, 30 * 1000 /* Timeout in ms */);
571 AssertRC(rc2);
572
573 if (!pTransfer->Thread.fStarted) /* Did the thread fail to start? */
574 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
575 }
576
577 LogFlowFuncLeaveRC(rc);
578 return rc;
579}
580
581/**
582 * Destroys a thread of a clipboard URI transfer.
583 *
584 * @returns VBox status code.
585 * @param pTransfer URI clipboard transfer struct to destroy thread for.
586 * @param uTimeoutMs Timeout (in ms) to wait for thread creation.
587 */
588static int sharedClipboardURITransferThreadDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer, RTMSINTERVAL uTimeoutMs)
589{
590 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
591
592 if (pTransfer->Thread.hThread == NIL_RTTHREAD)
593 return VINF_SUCCESS;
594
595 int rcThread = VERR_WRONG_ORDER;
596 int rc = RTThreadWait(pTransfer->Thread.hThread, uTimeoutMs, &rcThread);
597
598 LogFlowFunc(("Waiting for thread resulted in %Rrc (thread exited with %Rrc)\n", rc, rcThread));
599
600 return rc;
601}
602
603/**
604 * Reads all URI objects using the connected provider.
605 *
606 * @returns VBox status code.
607 * @param pTransfer Transfer to read objects for.
608 */
609int SharedClipboardURITransferRead(PSHAREDCLIPBOARDURITRANSFER pTransfer)
610{
611 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
612
613 LogFlowFuncEnter();
614
615 int rc = SharedClipboardURITransferMetaDataRead(pTransfer, NULL /* pcbRead */);
616 if (RT_SUCCESS(rc))
617 rc = SharedClipboardURITransferWriteObjects(pTransfer);
618
619 LogFlowFuncLeaveRC(rc);
620 return rc;
621}
622
623/**
624 * Thread for transferring (reading) URI objects from source to the target.
625 * For target to source transfers we utilize our own IDataObject / IStream implementations.
626 *
627 * @returns VBox status code.
628 * @param hThread Thread handle.
629 * @param pvUser User arguments; is PSHAREDCLIPBOARDURITRANSFER.
630 */
631static int sharedClipboardURITransferReadThread(RTTHREAD hThread, void *pvUser)
632{
633 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
634
635 LogFlowFuncEnter();
636
637 /* At the moment we only support one transfer at a time. */
638 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)pvUser;
639 AssertPtr(pTransfer->pProvider);
640
641 int rc = VINF_SUCCESS;
642
643 if (RT_SUCCESS(rc))
644 pTransfer->Thread.fStarted = true;
645
646 int rc2 = RTThreadUserSignal(hThread);
647 const bool fSignalled = RT_SUCCESS(rc2);
648
649 if (RT_SUCCESS(rc))
650 rc = SharedClipboardURITransferRead(pTransfer);
651
652 if (!fSignalled)
653 {
654 rc2 = RTThreadUserSignal(hThread);
655 AssertRC(rc2);
656 }
657
658 LogFlowFuncLeaveRC(rc);
659 return rc;
660}
661
662/**
663 * Adds meta data for a clipboard URI transfer, internal version.
664 *
665 * @returns VBox status code.
666 * @param pTransfer URI clipboard transfer struct to set meta data for.
667 * @param pvMeta Pointer to meta data buffer.
668 * @param cbMeta Size (in bytes) of meta data buffer.
669 */
670static int sharedClipboardURITransferMetaDataAddInternal(PSHAREDCLIPBOARDURITRANSFER pTransfer, const void *pvMeta, uint32_t cbMeta)
671{
672 LogFlowFuncEnter();
673
674 int rc = SharedClipboardMetaDataAdd(&pTransfer->Meta, pvMeta, cbMeta);
675 if (RT_SUCCESS(rc))
676 {
677 /** @todo Accounting? */
678 }
679
680 LogFlowFuncLeaveRC(rc);
681 return rc;
682}
683
684/**
685 * Adds meta data for a clipboard URI transfer.
686 *
687 * @returns VBox status code.
688 * @param pTransfer URI clipboard transfer struct to set meta data for.
689 * @param pvMeta Pointer to meta data buffer.
690 * @param cbMeta Size (in bytes) of meta data buffer.
691 */
692int SharedClipboardURITransferMetaDataAdd(PSHAREDCLIPBOARDURITRANSFER pTransfer, const void *pvMeta, uint32_t cbMeta)
693{
694 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
695
696 int rc = sharedClipboardURITransferMetaDataAddInternal(pTransfer, pvMeta, cbMeta);
697
698 LogFlowFuncLeaveRC(rc);
699 return rc;
700}
701
702int SharedClipboardURITransferMetaDataRead(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint32_t *pcbRead)
703{
704 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
705
706 /* Destroy any former meta data. */
707 SharedClipboardMetaDataDestroy(&pTransfer->Meta);
708
709 uint32_t cbReadTotal = 0;
710
711 int rc = pTransfer->pProvider->ReadDataHdr(&pTransfer->Header);
712 if (RT_SUCCESS(rc))
713 {
714 uint32_t cbMeta = _4K; /** @todo Improve. */
715 void *pvMeta = RTMemAlloc(cbMeta);
716
717 if (pvMeta)
718 {
719 uint32_t cbMetaToRead = pTransfer->Header.cbMeta;
720 while (cbMetaToRead)
721 {
722 uint32_t cbMetaRead;
723 rc = pTransfer->pProvider->ReadMetaData(&pTransfer->Header, pvMeta, cbMeta, &cbMetaRead);
724 if (RT_SUCCESS(rc))
725 rc = sharedClipboardURITransferMetaDataAddInternal(pTransfer, pvMeta, cbMeta);
726
727 if (RT_FAILURE(rc))
728 break;
729
730 Assert(cbMetaToRead >= cbMetaRead);
731 cbMetaToRead -= cbMetaRead;
732
733 cbReadTotal += cbReadTotal;
734 }
735
736 RTMemFree(pvMeta);
737
738 if (RT_SUCCESS(rc))
739 {
740 if (pcbRead)
741 *pcbRead = cbReadTotal;
742 }
743 }
744 else
745 rc = VERR_NO_MEMORY;
746 }
747
748 LogFlowFuncLeaveRC(rc);
749 return rc;
750}
751
752/**
753 * Writes the actual meta data.
754 *
755 * @returns IPRT status code.
756 * @param pTransfer Transfer to write meta data for.
757 * @param pcbWritten How much bytes were written on success. Optional.
758 */
759int SharedClipboardURITransferMetaDataWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint32_t *pcbWritten)
760{
761 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
762
763 AssertPtr(pTransfer->pProvider);
764
765 uint32_t cbWrittenTotal = 0;
766
767 int rc = pTransfer->pProvider->WriteDataHdr(&pTransfer->Header);
768 if (RT_SUCCESS(rc))
769 {
770 /* Sanity. */
771 Assert(pTransfer->Header.cbMeta == pTransfer->Meta.cbUsed);
772
773 uint32_t cbMetaToWrite = pTransfer->Header.cbMeta;
774 while (cbMetaToWrite)
775 {
776 uint32_t cbMetaWritten;
777 rc = pTransfer->pProvider->WriteMetaData(&pTransfer->Header, (uint8_t *)pTransfer->Meta.pvMeta + cbWrittenTotal,
778 cbMetaToWrite, &cbMetaWritten, 0 /* fFlags */);
779 if (RT_SUCCESS(rc))
780 {
781 cbWrittenTotal += cbMetaWritten;
782 Assert(cbWrittenTotal <= pTransfer->Header.cbMeta);
783 }
784 }
785
786 if (RT_SUCCESS(rc))
787 {
788 if (pcbWritten)
789 *pcbWritten = cbWrittenTotal;
790 }
791 }
792
793 LogFlowFuncLeaveRC(rc);
794 return rc;
795}
796
797/**
798 * Writes all URI objects using the connected provider.
799 *
800 * @returns VBox status code.
801 * @param pTransfer Transfer to write objects for.
802 */
803int SharedClipboardURITransferWriteObjects(PSHAREDCLIPBOARDURITRANSFER pTransfer)
804{
805 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
806
807 LogFlowFuncEnter();
808
809 int rc = VINF_SUCCESS;
810
811 AssertPtr(pTransfer->pProvider);
812
813 while (!pTransfer->URIList.IsEmpty())
814 {
815 SharedClipboardURIObject *pObj = pTransfer->URIList.First();
816 AssertPtrBreakStmt(pObj, rc = VERR_INVALID_POINTER);
817
818 switch (pObj->GetType())
819 {
820 case SharedClipboardURIObject::Type_Directory:
821 {
822 VBOXCLIPBOARDDIRDATA dirData;
823 RT_ZERO(dirData);
824
825 dirData.pszPath = RTStrDup(pObj->GetDestPathAbs().c_str());
826 dirData.cbPath = (uint32_t)strlen(dirData.pszPath);
827
828 rc = pTransfer->pProvider->WriteDirectory(&dirData);
829 break;
830 }
831
832 case SharedClipboardURIObject::Type_File:
833 {
834 VBOXCLIPBOARDFILEHDR fileHdr;
835 RT_ZERO(fileHdr);
836
837 fileHdr.pszFilePath = RTStrDup(pObj->GetDestPathAbs().c_str());
838 fileHdr.cbFilePath = (uint32_t)strlen(fileHdr.pszFilePath);
839 fileHdr.cbSize = pObj->GetSize();
840 fileHdr.fFlags = 0;
841 fileHdr.fMode = pObj->GetMode();
842
843 rc = pTransfer->pProvider->WriteFileHdr(&fileHdr);
844 if (RT_FAILURE(rc))
845 break;
846
847 uint32_t cbData = _4K; /** @todo Improve. */
848 void *pvData = RTMemAlloc(cbData);
849
850 while (!pObj->IsComplete())
851 {
852 VBOXCLIPBOARDFILEDATA fileData;
853 RT_ZERO(fileData);
854
855 uint32_t cbRead;
856 rc = pObj->Read(pvData, cbData, &cbRead);
857 if (RT_SUCCESS(rc))
858 {
859 fileData.pvData = pvData;
860 fileData.cbData = cbRead;
861
862 uint32_t cbWritten;
863 rc = pTransfer->pProvider->WriteFileData(&fileData, &cbWritten);
864 }
865
866 if (RT_FAILURE(rc))
867 break;
868 }
869 break;
870 }
871
872 default:
873 AssertFailed();
874 break;
875 }
876
877 if (RT_FAILURE(rc))
878 break;
879
880 /* Only remove current object on success. */
881 pTransfer->URIList.RemoveFirst();
882 }
883
884 LogFlowFuncLeaveRC(rc);
885 return rc;
886}
887
888/**
889 * Thread for transferring (writing) URI objects from source to the target.
890 * For target to source transfers we utilize our own IDataObject / IStream implementations.
891 *
892 * @returns VBox status code.
893 * @param hThread Thread handle.
894 * @param pvUser User arguments; is PSHAREDCLIPBOARDURITRANSFER.
895 */
896static int sharedClipboardURITransferWriteThread(RTTHREAD hThread, void *pvUser)
897{
898 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
899
900 LogFlowFuncEnter();
901
902 /* At the moment we only support one transfer at a time. */
903 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)pvUser;
904 AssertPtr(pTransfer->pProvider);
905
906 int rc = VINF_SUCCESS;
907
908 if (RT_SUCCESS(rc))
909 pTransfer->Thread.fStarted = true;
910
911 int rc2 = RTThreadUserSignal(hThread);
912 const bool fSignalled = RT_SUCCESS(rc2);
913
914 if (RT_SUCCESS(rc))
915 rc = SharedClipboardURITransferWrite(pTransfer);
916
917 if (!fSignalled)
918 {
919 rc2 = RTThreadUserSignal(hThread);
920 AssertRC(rc2);
921 }
922
923 LogFlowFuncLeaveRC(rc);
924 return rc;
925}
926
927/**
928 * Main function to write a clipboard URI transfer.
929 *
930 * @returns VBox status code.
931 * @param pURI URI clipboard context to write.
932 */
933int SharedClipboardURITransferWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer)
934{
935 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
936
937 int rc = SharedClipboardURITransferMetaDataWrite(pTransfer, NULL /* pcbWritten */);
938 if (RT_SUCCESS(rc))
939 rc = SharedClipboardURITransferWriteObjects(pTransfer);
940
941 LogFlowFuncLeaveRC(rc);
942 return rc;
943}
944
945/**
946 * Initializes a clipboard URI transfer.
947 *
948 * @returns VBox status code.
949 * @param pURI URI clipboard context to initialize.
950 */
951int SharedClipboardURICtxInit(PSHAREDCLIPBOARDURICTX pURI)
952{
953 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
954
955 LogFlowFuncEnter();
956
957 int rc = RTCritSectInit(&pURI->CritSect);
958 if (RT_SUCCESS(rc))
959 {
960 RTListInit(&pURI->List);
961
962 pURI->cTransfers = 0;
963
964 SharedClipboardURICtxReset(pURI);
965 }
966
967 return VINF_SUCCESS;
968}
969
970/**
971 * Destroys an URI clipboard information context struct.
972 *
973 * @param pURI URI clipboard context to destroy.
974 */
975void SharedClipboardURICtxDestroy(PSHAREDCLIPBOARDURICTX pURI)
976{
977 AssertPtrReturnVoid(pURI);
978
979 RTCritSectDelete(&pURI->CritSect);
980
981 PSHAREDCLIPBOARDURITRANSFER pTransfer, pTransferNext;
982 RTListForEachSafe(&pURI->List, pTransfer, pTransferNext, SHAREDCLIPBOARDURITRANSFER, Node)
983 {
984 SharedClipboardURITransferDestroy(pTransfer);
985 RTListNodeRemove(&pTransfer->Node);
986 }
987
988 LogFlowFuncEnter();
989}
990
991/**
992 * Resets an clipboard URI transfer.
993 *
994 * @param pURI URI clipboard context to reset.
995 */
996void SharedClipboardURICtxReset(PSHAREDCLIPBOARDURICTX pURI)
997{
998 AssertPtrReturnVoid(pURI);
999
1000 LogFlowFuncEnter();
1001
1002 PSHAREDCLIPBOARDURITRANSFER pTransfer;
1003 RTListForEach(&pURI->List, pTransfer, SHAREDCLIPBOARDURITRANSFER, Node)
1004 SharedClipboardURITransferReset(pTransfer);
1005}
1006
1007/**
1008 * Adds a new URI transfer to an clipboard URI transfer.
1009 *
1010 * @returns VBox status code.
1011 * @param pURI URI clipboard context to add transfer to.
1012 * @param pTransfer Pointer to URI clipboard transfer struct to add.
1013 */
1014int SharedClipboardURICtxTransferAdd(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
1015{
1016 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
1017 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1018
1019 LogFlowFuncEnter();
1020
1021 if (pURI->cTransfers) /* Only one transfer per URI context allowed at the moment. */
1022 return VERR_ALREADY_EXISTS;
1023
1024 RTListAppend(&pURI->List, &pTransfer->Node);
1025 pURI->cTransfers++;
1026
1027 return VINF_SUCCESS;
1028}
1029
1030/**
1031 * Removes an URI transfer from a clipboard URI transfer.
1032 *
1033 * @returns VBox status code.
1034 * @param pURI URI clipboard context to remove transfer from.
1035 * @param pTransfer Pointer to URI clipboard transfer struct to remove.
1036 */
1037int SharedClipboardURICtxTransferRemove(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
1038{
1039 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
1040 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1041
1042 LogFlowFuncEnter();
1043
1044 /* Sanity. */
1045 AssertReturn(pURI->cTransfers, VERR_WRONG_ORDER);
1046
1047 int rc = SharedClipboardURITransferDestroy(pTransfer);
1048 if (RT_SUCCESS(rc))
1049 {
1050
1051 RTListNodeRemove(&pTransfer->Node);
1052 pURI->cTransfers--;
1053 }
1054
1055 LogFlowFuncLeaveRC(rc);
1056 return rc;
1057}
1058
1059/**
1060 * Returns a specific URI transfer, internal version.
1061 *
1062 * @returns URI transfer, or NULL if not found.
1063 * @param pURI URI clipboard context to return transfer for.
1064 * @param uIdx Index of the transfer to return.
1065 */
1066static PSHAREDCLIPBOARDURITRANSFER sharedClipboardURICtxGetTransferInternal(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
1067{
1068 AssertReturn(uIdx == 0, NULL); /* Only one transfer allowed at the moment. */
1069 return RTListGetFirst(&pURI->List, SHAREDCLIPBOARDURITRANSFER, Node);
1070}
1071
1072/**
1073 * Returns a specific URI transfer.
1074 *
1075 * @returns URI transfer, or NULL if not found.
1076 * @param pURI URI clipboard context to return transfer for.
1077 * @param uIdx Index of the transfer to return.
1078 */
1079PSHAREDCLIPBOARDURITRANSFER SharedClipboardURICtxGetTransfer(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
1080{
1081 return sharedClipboardURICtxGetTransferInternal(pURI, uIdx);
1082}
1083
1084/**
1085 * Returns the number of active URI transfers.
1086 *
1087 * @returns VBox status code.
1088 * @param pURI URI clipboard context to return number for.
1089 */
1090uint32_t SharedClipboardURICtxGetActiveTransfers(PSHAREDCLIPBOARDURICTX pURI)
1091{
1092 AssertPtrReturn(pURI, 0);
1093 return pURI->cTransfers;
1094}
1095#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
1096
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