VirtualBox

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

Last change on this file since 79174 was 79174, 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: 44.6 KB
Line 
1/* $Id: clipboard-common.cpp 79174 2019-06-17 10:30:49Z 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/path.h>
25
26#include <VBox/err.h>
27#include <VBox/log.h>
28#include <VBox/GuestHost/clipboard-helper.h>
29#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
30# include <VBox/GuestHost/SharedClipboard-uri.h>
31#endif
32
33
34#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
35static int sharedClipboardURITransferThreadCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer);
36static int sharedClipboardURITransferThreadDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer, RTMSINTERVAL uTimeoutMs);
37static int sharedClipboardURITransferReadThread(RTTHREAD hThread, void *pvUser);
38static int sharedClipboardURITransferWriteThread(RTTHREAD hThread, void *pvUser);
39static PSHAREDCLIPBOARDURITRANSFER sharedClipboardURICtxGetTransferInternal(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx);
40#endif
41
42
43/** @todo use const where appropriate; delinuxify the code (*Lin* -> *Host*); use AssertLogRel*. */
44
45int vboxClipboardUtf16GetWinSize(PRTUTF16 pwszSrc, size_t cwSrc, size_t *pcwDest)
46{
47 size_t cwDest, i;
48
49 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
50 AssertLogRelMsgReturn(pwszSrc != NULL, ("vboxClipboardUtf16GetWinSize: received a null Utf16 string, returning VERR_INVALID_PARAMETER\n"), VERR_INVALID_PARAMETER);
51 if (cwSrc == 0)
52 {
53 *pcwDest = 0;
54 LogFlowFunc(("empty source string, returning\n"));
55 return VINF_SUCCESS;
56 }
57/** @todo convert the remainder of the Assert stuff to AssertLogRel. */
58 /* We only take little endian Utf16 */
59 if (pwszSrc[0] == UTF16BEMARKER)
60 {
61 LogRel(("vboxClipboardUtf16GetWinSize: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
62 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
63 }
64 cwDest = 0;
65 /* Calculate the size of the destination text string. */
66 /* Is this Utf16 or Utf16-LE? */
67 for (i = (pwszSrc[0] == UTF16LEMARKER ? 1 : 0); i < cwSrc; ++i, ++cwDest)
68 {
69 /* Check for a single line feed */
70 if (pwszSrc[i] == LINEFEED)
71 ++cwDest;
72#ifdef RT_OS_DARWIN
73 /* Check for a single carriage return (MacOS) */
74 if (pwszSrc[i] == CARRIAGERETURN)
75 ++cwDest;
76#endif
77 if (pwszSrc[i] == 0)
78 {
79 /* Don't count this, as we do so below. */
80 break;
81 }
82 }
83 /* Count the terminating null byte. */
84 ++cwDest;
85 LogFlowFunc(("returning VINF_SUCCESS, %d 16bit words\n", cwDest));
86 *pcwDest = cwDest;
87 return VINF_SUCCESS;
88}
89
90int vboxClipboardUtf16LinToWin(PRTUTF16 pwszSrc, size_t cwSrc, PRTUTF16 pu16Dest,
91 size_t cwDest)
92{
93 size_t i, j;
94 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
95 if (!VALID_PTR(pwszSrc) || !VALID_PTR(pu16Dest))
96 {
97 LogRel(("vboxClipboardUtf16LinToWin: received an invalid pointer, pwszSrc=%p, pu16Dest=%p, returning VERR_INVALID_PARAMETER\n", pwszSrc, pu16Dest));
98 AssertReturn(VALID_PTR(pwszSrc) && VALID_PTR(pu16Dest), VERR_INVALID_PARAMETER);
99 }
100 if (cwSrc == 0)
101 {
102 if (cwDest == 0)
103 {
104 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
105 return VERR_BUFFER_OVERFLOW;
106 }
107 pu16Dest[0] = 0;
108 LogFlowFunc(("empty source string, returning\n"));
109 return VINF_SUCCESS;
110 }
111 /* We only take little endian Utf16 */
112 if (pwszSrc[0] == UTF16BEMARKER)
113 {
114 LogRel(("vboxClipboardUtf16LinToWin: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
115 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
116 }
117 /* Don't copy the endian marker. */
118 for (i = (pwszSrc[0] == UTF16LEMARKER ? 1 : 0), j = 0; i < cwSrc; ++i, ++j)
119 {
120 /* Don't copy the null byte, as we add it below. */
121 if (pwszSrc[i] == 0)
122 break;
123 if (j == cwDest)
124 {
125 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
126 return VERR_BUFFER_OVERFLOW;
127 }
128 if (pwszSrc[i] == LINEFEED)
129 {
130 pu16Dest[j] = CARRIAGERETURN;
131 ++j;
132 if (j == cwDest)
133 {
134 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
135 return VERR_BUFFER_OVERFLOW;
136 }
137 }
138#ifdef RT_OS_DARWIN
139 /* Check for a single carriage return (MacOS) */
140 else if (pwszSrc[i] == CARRIAGERETURN)
141 {
142 /* set cr */
143 pu16Dest[j] = CARRIAGERETURN;
144 ++j;
145 if (j == cwDest)
146 {
147 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
148 return VERR_BUFFER_OVERFLOW;
149 }
150 /* add the lf */
151 pu16Dest[j] = LINEFEED;
152 continue;
153 }
154#endif
155 pu16Dest[j] = pwszSrc[i];
156 }
157 /* Add the trailing null. */
158 if (j == cwDest)
159 {
160 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
161 return VERR_BUFFER_OVERFLOW;
162 }
163 pu16Dest[j] = 0;
164 LogFlowFunc(("rc=VINF_SUCCESS, pu16Dest=%ls\n", pu16Dest));
165 return VINF_SUCCESS;
166}
167
168int vboxClipboardUtf16GetLinSize(PRTUTF16 pwszSrc, size_t cwSrc, size_t *pcwDest)
169{
170 size_t cwDest;
171
172 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
173 if (!VALID_PTR(pwszSrc))
174 {
175 LogRel(("vboxClipboardUtf16GetLinSize: received an invalid Utf16 string %p. Returning VERR_INVALID_PARAMETER.\n", pwszSrc));
176 AssertReturn(VALID_PTR(pwszSrc), VERR_INVALID_PARAMETER);
177 }
178 if (cwSrc == 0)
179 {
180 LogFlowFunc(("empty source string, returning VINF_SUCCESS\n"));
181 *pcwDest = 0;
182 return VINF_SUCCESS;
183 }
184 /* We only take little endian Utf16 */
185 if (pwszSrc[0] == UTF16BEMARKER)
186 {
187 LogRel(("vboxClipboardUtf16GetLinSize: received a big endian Utf16 string. Returning VERR_INVALID_PARAMETER.\n"));
188 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
189 }
190 /* Calculate the size of the destination text string. */
191 /* Is this Utf16 or Utf16-LE? */
192 if (pwszSrc[0] == UTF16LEMARKER)
193 cwDest = 0;
194 else
195 cwDest = 1;
196 for (size_t i = 0; i < cwSrc; ++i, ++cwDest)
197 {
198 if ( (i + 1 < cwSrc)
199 && (pwszSrc[i] == CARRIAGERETURN)
200 && (pwszSrc[i + 1] == LINEFEED))
201 {
202 ++i;
203 }
204 if (pwszSrc[i] == 0)
205 {
206 break;
207 }
208 }
209 /* Terminating zero */
210 ++cwDest;
211 LogFlowFunc(("returning %d\n", cwDest));
212 *pcwDest = cwDest;
213 return VINF_SUCCESS;
214}
215
216int vboxClipboardUtf16WinToLin(PRTUTF16 pwszSrc, size_t cwSrc, PRTUTF16 pu16Dest,
217 size_t cwDest)
218{
219 size_t cwDestPos;
220
221 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u, pu16Dest=%p, cwDest=%u\n",
222 cwSrc, pwszSrc, cwSrc, pu16Dest, cwDest));
223 /* A buffer of size 0 may not be an error, but it is not a good idea either. */
224 Assert(cwDest > 0);
225 if (!VALID_PTR(pwszSrc) || !VALID_PTR(pu16Dest))
226 {
227 LogRel(("vboxClipboardUtf16WinToLin: received an invalid ptr, pwszSrc=%p, pu16Dest=%p, returning VERR_INVALID_PARAMETER\n", pwszSrc, pu16Dest));
228 AssertReturn(VALID_PTR(pwszSrc) && VALID_PTR(pu16Dest), VERR_INVALID_PARAMETER);
229 }
230 /* We only take little endian Utf16 */
231 if (pwszSrc[0] == UTF16BEMARKER)
232 {
233 LogRel(("vboxClipboardUtf16WinToLin: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
234 AssertMsgFailedReturn(("received a big endian string\n"), VERR_INVALID_PARAMETER);
235 }
236 if (cwDest == 0)
237 {
238 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
239 return VERR_BUFFER_OVERFLOW;
240 }
241 if (cwSrc == 0)
242 {
243 pu16Dest[0] = 0;
244 LogFlowFunc(("received empty string. Returning VINF_SUCCESS\n"));
245 return VINF_SUCCESS;
246 }
247 /* Prepend the Utf16 byte order marker if it is missing. */
248 if (pwszSrc[0] == UTF16LEMARKER)
249 {
250 cwDestPos = 0;
251 }
252 else
253 {
254 pu16Dest[0] = UTF16LEMARKER;
255 cwDestPos = 1;
256 }
257 for (size_t i = 0; i < cwSrc; ++i, ++cwDestPos)
258 {
259 if (pwszSrc[i] == 0)
260 {
261 break;
262 }
263 if (cwDestPos == cwDest)
264 {
265 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
266 return VERR_BUFFER_OVERFLOW;
267 }
268 if ( (i + 1 < cwSrc)
269 && (pwszSrc[i] == CARRIAGERETURN)
270 && (pwszSrc[i + 1] == LINEFEED))
271 {
272 ++i;
273 }
274 pu16Dest[cwDestPos] = pwszSrc[i];
275 }
276 /* Terminating zero */
277 if (cwDestPos == cwDest)
278 {
279 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
280 return VERR_BUFFER_OVERFLOW;
281 }
282 pu16Dest[cwDestPos] = 0;
283 LogFlowFunc(("set string %ls. Returning\n", pu16Dest + 1));
284 return VINF_SUCCESS;
285}
286
287int vboxClipboardDibToBmp(const void *pvSrc, size_t cbSrc, void **ppvDest, size_t *pcbDest)
288{
289 size_t cb = sizeof(BMFILEHEADER) + cbSrc;
290 PBMFILEHEADER pFileHeader = NULL;
291 void *pvDest = NULL;
292 size_t offPixel = 0;
293
294 AssertPtrReturn(pvSrc, VERR_INVALID_PARAMETER);
295 AssertPtrReturn(ppvDest, VERR_INVALID_PARAMETER);
296 AssertPtrReturn(pcbDest, VERR_INVALID_PARAMETER);
297
298 PBMINFOHEADER pBitmapInfoHeader = (PBMINFOHEADER)pvSrc;
299 /** @todo Support all the many versions of the DIB headers. */
300 if ( cbSrc < sizeof(BMINFOHEADER)
301 || RT_LE2H_U32(pBitmapInfoHeader->u32Size) < sizeof(BMINFOHEADER)
302 || RT_LE2H_U32(pBitmapInfoHeader->u32Size) != sizeof(BMINFOHEADER))
303 {
304 Log(("vboxClipboardDibToBmp: invalid or unsupported bitmap data.\n"));
305 return VERR_INVALID_PARAMETER;
306 }
307
308 offPixel = sizeof(BMFILEHEADER)
309 + RT_LE2H_U32(pBitmapInfoHeader->u32Size)
310 + RT_LE2H_U32(pBitmapInfoHeader->u32ClrUsed) * sizeof(uint32_t);
311 if (cbSrc < offPixel)
312 {
313 Log(("vboxClipboardDibToBmp: invalid bitmap data.\n"));
314 return VERR_INVALID_PARAMETER;
315 }
316
317 pvDest = RTMemAlloc(cb);
318 if (!pvDest)
319 {
320 Log(("writeToPasteboard: cannot allocate memory for bitmap.\n"));
321 return VERR_NO_MEMORY;
322 }
323
324 pFileHeader = (PBMFILEHEADER)pvDest;
325 pFileHeader->u16Type = BITMAPHEADERMAGIC;
326 pFileHeader->u32Size = (uint32_t)RT_H2LE_U32(cb);
327 pFileHeader->u16Reserved1 = pFileHeader->u16Reserved2 = 0;
328 pFileHeader->u32OffBits = (uint32_t)RT_H2LE_U32(offPixel);
329 memcpy((uint8_t *)pvDest + sizeof(BMFILEHEADER), pvSrc, cbSrc);
330 *ppvDest = pvDest;
331 *pcbDest = cb;
332 return VINF_SUCCESS;
333}
334
335int vboxClipboardBmpGetDib(const void *pvSrc, size_t cbSrc, const void **ppvDest, size_t *pcbDest)
336{
337 AssertPtrReturn(pvSrc, VERR_INVALID_PARAMETER);
338 AssertPtrReturn(ppvDest, VERR_INVALID_PARAMETER);
339 AssertPtrReturn(pcbDest, VERR_INVALID_PARAMETER);
340
341 PBMFILEHEADER pFileHeader = (PBMFILEHEADER)pvSrc;
342 if ( cbSrc < sizeof(BMFILEHEADER)
343 || pFileHeader->u16Type != BITMAPHEADERMAGIC
344 || RT_LE2H_U32(pFileHeader->u32Size) != cbSrc)
345 {
346 Log(("vboxClipboardBmpGetDib: invalid bitmap data.\n"));
347 return VERR_INVALID_PARAMETER;
348 }
349
350 *ppvDest = ((uint8_t *)pvSrc) + sizeof(BMFILEHEADER);
351 *pcbDest = cbSrc - sizeof(BMFILEHEADER);
352 return VINF_SUCCESS;
353}
354
355#ifdef VBOX_STRICT
356int vboxClipboardDbgDumpHtml(const char *pszSrc, size_t cbSrc)
357{
358 size_t cchIgnored = 0;
359 int rc = RTStrNLenEx(pszSrc, cbSrc, &cchIgnored);
360 if (RT_SUCCESS(rc))
361 {
362 char *pszBuf = (char *)RTMemAllocZ(cbSrc + 1);
363 if (pszBuf)
364 {
365 rc = RTStrCopy(pszBuf, cbSrc + 1, (const char *)pszSrc);
366 if (RT_SUCCESS(rc))
367 {
368 for (size_t i = 0; i < cbSrc; ++i)
369 if (pszBuf[i] == '\n' || pszBuf[i] == '\r')
370 pszBuf[i] = ' ';
371 }
372 else
373 LogFunc(("Error in copying string\n"));
374 LogFunc(("Removed \\r\\n: %s\n", pszBuf));
375 RTMemFree(pszBuf);
376 }
377 else
378 rc = VERR_NO_MEMORY;
379 }
380
381 return rc;
382}
383#endif
384
385#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
386/**
387 * Returns the size (in bytes) of the announced meta data.
388 *
389 * @returns Announced meta data size in bytes.
390 * @param pDataHdr Data header struct to get announced meta data size for.
391 */
392uint32_t SharedClipboardURIDataHdrGetMetaDataSize(PVBOXCLIPBOARDDATAHDR pDataHdr)
393{
394 AssertPtrReturn(pDataHdr, 0);
395
396 return pDataHdr->cbMeta;
397}
398
399/**
400 * Initializes an URI data header struct.
401 *
402 * @returns VBox status code.
403 * @param pDataHdr Data header struct to initialize.
404 */
405int SharedClipboardURIDataHdrInit(PVBOXCLIPBOARDDATAHDR pDataHdr)
406{
407 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
408
409 SharedClipboardURIDataHdrReset(pDataHdr);
410
411 return VINF_SUCCESS;
412}
413
414/**
415 * Destroys an URI data header struct.
416 *
417 * @param pDataHdr Data header struct to destroy.
418 */
419void SharedClipboardURIDataHdrDestroy(PVBOXCLIPBOARDDATAHDR pDataHdr)
420{
421 if (!pDataHdr)
422 return;
423
424 if (pDataHdr->pvMetaFmt)
425 {
426 Assert(pDataHdr->cbMetaFmt);
427
428 PSHAREDCLIPBOARDMETADATAFMT pMetaDatafmt = (PSHAREDCLIPBOARDMETADATAFMT)pDataHdr->pvMetaFmt;
429 AssertPtr(pMetaDatafmt);
430 if (pMetaDatafmt->pvFmt)
431 {
432 Assert(pMetaDatafmt->cbFmt);
433 RTMemFree(pMetaDatafmt->pvFmt);
434 }
435
436 RTMemFree(pDataHdr->pvMetaFmt);
437 pDataHdr->pvMetaFmt = NULL;
438 pDataHdr->cbMetaFmt = 0;
439 }
440
441 if (pDataHdr->pvChecksum)
442 {
443 Assert(pDataHdr->cbChecksum);
444
445 RTMemFree(pDataHdr->pvChecksum);
446 pDataHdr->pvChecksum = NULL;
447 pDataHdr->cbChecksum = 0;
448 }
449}
450
451/**
452 * Resets an URI data header struct.
453 *
454 * @returns VBox status code.
455 * @param pDataHdr Data header struct to reset.
456 */
457void SharedClipboardURIDataHdrReset(PVBOXCLIPBOARDDATAHDR pDataHdr)
458{
459 AssertPtrReturnVoid(pDataHdr);
460
461 LogFlowFuncEnter();
462
463 RT_BZERO(pDataHdr, sizeof(VBOXCLIPBOARDDATAHDR));
464}
465
466/**
467 * Returns whether a given clipboard data header is valid or not.
468 *
469 * @returns \c true if valid, \c false if not.
470 * @param pDataHdr Clipboard data header to validate.
471 */
472bool SharedClipboardURIDataHdrIsValid(PVBOXCLIPBOARDDATAHDR pDataHdr)
473{
474 RT_NOREF(pDataHdr);
475 return true; /** @todo Implement this. */
476}
477
478/**
479 * Returns whether a given clipboard data chunk is valid or not.
480 *
481 * @returns \c true if valid, \c false if not.
482 * @param pDataChunk Clipboard data chunk to validate.
483 */
484bool SharedClipboardURIDataChunkIsValid(PVBOXCLIPBOARDDATACHUNK pDataChunk)
485{
486 RT_NOREF(pDataChunk);
487 return true; /** @todo Implement this. */
488}
489
490/**
491 * Returns whether given clipboard directory data is valid or not.
492 *
493 * @returns \c true if valid, \c false if not.
494 * @param pDirData Clipboard directory data to validate.
495 */
496bool SharedClipboardURIDirDataIsValid(PVBOXCLIPBOARDDIRDATA pDirData)
497{
498 if ( !pDirData->cbPath
499 || pDirData->cbPath > RTPATH_MAX)
500 return false;
501
502 if (!RTStrIsValidEncoding(pDirData->pszPath))
503 return false;
504
505 return true;
506}
507
508/**
509 * Returns whether a given clipboard file header is valid or not.
510 *
511 * @returns \c true if valid, \c false if not.
512 * @param pFileHdr Clipboard file header to validate.
513 * @param pDataHdr Data header to use for validation.
514 */
515bool SharedClipboardURIFileHdrIsValid(PVBOXCLIPBOARDFILEHDR pFileHdr, PVBOXCLIPBOARDDATAHDR pDataHdr)
516{
517 if ( !pFileHdr->cbFilePath
518 || pFileHdr->cbFilePath > RTPATH_MAX)
519 return false;
520
521 if (!RTStrIsValidEncoding(pFileHdr->pszFilePath))
522 return false;
523
524 if (pFileHdr->cbSize > pDataHdr->cbTotal)
525 return false;
526
527 return true;
528}
529
530/**
531 * Returns whether given clipboard file data is valid or not.
532 *
533 * @returns \c true if valid, \c false if not.
534 * @param pFileData Clipboard file data to validate.
535 * @param pDataHdr Data header to use for validation.
536 */
537bool SharedClipboardURIFileDataIsValid(PVBOXCLIPBOARDFILEDATA pFileData, PVBOXCLIPBOARDDATAHDR pDataHdr)
538{
539 RT_NOREF(pFileData, pDataHdr);
540 return true;
541}
542
543/**
544 * Initializes an URI object context.
545 *
546 * @returns VBox status code.
547 * @param pObjCtx URI object context to initialize.
548 */
549int SharedClipboardURIObjCtxInit(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
550{
551 AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER);
552
553 LogFlowFuncEnter();
554
555 pObjCtx->pObj = NULL;
556
557 return VINF_SUCCESS;
558}
559
560/**
561 * Uninitializes an URI object context.
562 *
563 * @param pObjCtx URI object context to uninitialize.
564 */
565void SharedClipboardURIObjCtxUninit(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
566{
567 AssertPtrReturnVoid(pObjCtx);
568
569 LogFlowFuncEnter();
570
571 if (pObjCtx->pObj)
572 {
573 pObjCtx->pObj->Close();
574 delete pObjCtx->pObj;
575 }
576
577 pObjCtx->pObj = NULL;
578}
579
580/**
581 * Returns the URI object context's URI object.
582 *
583 * @returns Pointer to the URI object context's URI object.
584 * @param pObjCtx URI object context to return the URI object for.
585 */
586SharedClipboardURIObject *SharedClipboardURIObjCtxGetObj(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
587{
588 AssertPtrReturn(pObjCtx, NULL);
589 return pObjCtx->pObj;
590}
591
592/**
593 * Returns if an URI object context is valid or not.
594 *
595 * @returns \c true if valid, \c false if not.
596 * @param pObjCtx URI object context to check.
597 */
598bool SharedClipboardURIObjCtxIsValid(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
599{
600 return ( pObjCtx
601 && pObjCtx->pObj
602 && pObjCtx->pObj->IsComplete() == false
603 && pObjCtx->pObj->IsOpen());
604}
605
606/**
607 * Initializes an URI clipboard transfer struct.
608 *
609 * @returns VBox status code.
610 * @param enmDir Transfer direction.
611 * @param pCtx Shared Clipboard provider creation context to use.
612 * @param ppTransfer Where to return the created URI transfer struct.
613 * Must be destroyed by SharedClipboardURITransferDestroy().
614 */
615int SharedClipboardURITransferCreate(SHAREDCLIPBOARDURITRANSFERDIR enmDir, PSHAREDCLIPBOARDPROVIDERCREATIONCTX pCtx,
616 PSHAREDCLIPBOARDURITRANSFER *ppTransfer)
617{
618 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
619 AssertPtrReturn(ppTransfer, VERR_INVALID_POINTER);
620
621 LogFlowFuncEnter();
622
623 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)RTMemAlloc(sizeof(SHAREDCLIPBOARDURITRANSFER));
624 if (!pTransfer)
625 return VERR_NO_MEMORY;
626
627 pTransfer->State.enmDir = enmDir;
628
629 int rc = SharedClipboardURIDataHdrInit(&pTransfer->State.Header);
630 if (RT_SUCCESS(rc))
631 {
632 rc = SharedClipboardMetaDataInit(&pTransfer->State.Meta);
633 if (RT_SUCCESS(rc))
634 {
635 pTransfer->pArea = NULL; /* Will be created later if needed. */
636 pTransfer->pProvider = SharedClipboardProvider::Create(pCtx);
637 if (pTransfer->pProvider)
638 {
639 pTransfer->Thread.hThread = NIL_RTTHREAD;
640 pTransfer->Thread.fCancelled = false;
641 pTransfer->Thread.fStarted = false;
642
643 pTransfer->pvUser = NULL;
644 pTransfer->cbUser = 0;
645
646 *ppTransfer = pTransfer;
647 }
648 else
649 rc = VERR_NO_MEMORY;
650 }
651 }
652
653 LogFlowFuncLeaveRC(rc);
654 return rc;
655}
656
657/**
658 * Destroys an URI clipboard transfer context struct.
659 *
660 * @returns VBox status code.
661 * @param pURI URI clipboard transfer to destroy.
662 */
663int SharedClipboardURITransferDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer)
664{
665 if (!pTransfer)
666 return VINF_SUCCESS;
667
668 LogFlowFuncEnter();
669
670 int rc = sharedClipboardURITransferThreadDestroy(pTransfer, 30 * 1000 /* Timeout in ms */);
671 if (RT_FAILURE(rc))
672 return rc;
673
674 SharedClipboardURIDataHdrDestroy(&pTransfer->State.Header);
675 SharedClipboardMetaDataDestroy(&pTransfer->State.Meta);
676
677 if (pTransfer->pProvider)
678 {
679 delete pTransfer->pProvider;
680 pTransfer->pProvider = NULL;
681 }
682
683 RTMemFree(pTransfer);
684 pTransfer = NULL;
685
686 LogFlowFuncLeave();
687
688 return VINF_SUCCESS;
689}
690
691/**
692 * Resets an clipboard URI transfer.
693 *
694 * @param pTransfer URI clipboard transfer to reset.
695 */
696void SharedClipboardURITransferReset(PSHAREDCLIPBOARDURITRANSFER pTransfer)
697{
698 AssertPtrReturnVoid(pTransfer);
699
700 LogFlowFuncEnter();
701
702 /** @todo Anything else to do here? */
703
704 if (pTransfer->pProvider)
705 pTransfer->pProvider->Reset();
706
707 pTransfer->URIList.Clear();
708}
709
710/**
711 * Returns the clipboard area for a clipboard URI transfer.
712 *
713 * @returns Current clipboard area, or NULL if none.
714 * @param pTransfer URI clipboard transfer to return clipboard area for.
715 */
716SharedClipboardArea *SharedClipboardURITransferGetArea(PSHAREDCLIPBOARDURITRANSFER pTransfer)
717{
718 AssertPtrReturn(pTransfer, NULL);
719
720 return pTransfer->pArea;
721}
722
723/**
724 * Returns the current URI object for a clipboard URI transfer.
725 *
726 * @returns Current URI object, or NULL if none.
727 * @param pTransfer URI clipboard transfer to return current URI object for.
728 */
729const SharedClipboardURIObject *SharedClipboardURITransferGetCurrentObject(PSHAREDCLIPBOARDURITRANSFER pTransfer)
730{
731 AssertPtrReturn(pTransfer, NULL);
732
733 return pTransfer->URIList.First();
734}
735
736/**
737 * Returns the provider for a clipboard URI transfer.
738 *
739 * @returns Current provider, or NULL if none.
740 * @param pTransfer URI clipboard transfer to return provider for.
741 */
742SharedClipboardProvider *SharedClipboardURITransferGetProvider(PSHAREDCLIPBOARDURITRANSFER pTransfer)
743{
744 AssertPtrReturn(pTransfer, NULL);
745
746 return pTransfer->pProvider;
747}
748
749/**
750 * Returns the URI list for a clipboard URI transfer.
751 *
752 * @returns Pointer to URI list.
753 * @param pTransfer URI clipboard transfer to return URI list for.
754 */
755SharedClipboardURIList *SharedClipboardURITransferGetList(PSHAREDCLIPBOARDURITRANSFER pTransfer)
756{
757 return &pTransfer->URIList;
758}
759
760/**
761 * Returns the current URI object for a clipboard URI transfer.
762 *
763 * @returns Pointer to URI object.
764 * @param pTransfer URI clipboard transfer to return URI object for.
765 */
766SharedClipboardURIObject *SharedClipboardURITransferGetObject(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint64_t uIdx)
767{
768 return pTransfer->URIList.At(uIdx);
769}
770
771/**
772 * Runs (starts) an URI transfer, either in synchronous or asynchronous (threaded) mode.
773 *
774 * @returns VBox status code.
775 * @param pTransfer URI clipboard transfer to run.
776 * @param fAsync Whether to run the transfer synchronously or asynchronously.
777 */
778int SharedClipboardURITransferRun(PSHAREDCLIPBOARDURITRANSFER pTransfer, bool fAsync)
779{
780 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
781
782 int rc;
783
784 LogFlowFunc(("fAsync=%RTbool\n", fAsync));
785
786 if (fAsync)
787 {
788 rc = sharedClipboardURITransferThreadCreate(pTransfer);
789 }
790 else
791 {
792 if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_READ)
793 rc = SharedClipboardURITransferRead(pTransfer);
794 else if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_WRITE)
795 rc = SharedClipboardURITransferWrite(pTransfer);
796 else
797 rc = VERR_NOT_IMPLEMENTED;
798 }
799
800 LogFlowFuncLeaveRC(rc);
801 return rc;
802}
803
804/**
805 * Sets or unsets the callback table to be used for a clipboard URI transfer.
806 *
807 * @returns VBox status code.
808 * @param pTransfer URI clipboard transfer to set callbacks for.
809 * @param pCallbacks Pointer to callback table to set. Specify NULL to unset existing callbacks.
810 */
811void SharedClipboardURITransferSetCallbacks(PSHAREDCLIPBOARDURITRANSFER pTransfer, PSHAREDCLIPBOARDURITRANSFERCALLBACKS pCallbacks)
812{
813 AssertPtrReturnVoid(pTransfer);
814 /* pCallbacks might be NULL to unset callbacks. */
815
816 LogFlowFunc(("pCallbacks=%p\n", pCallbacks));
817
818 if (pCallbacks)
819 {
820 pTransfer->Callbacks = *pCallbacks;
821 }
822 else
823 RT_ZERO(pTransfer->Callbacks);
824}
825
826/**
827 * Creates a thread for a clipboard URI transfer.
828 *
829 * @returns VBox status code.
830 * @param pTransfer URI clipboard transfer to create thread for.
831 */
832static int sharedClipboardURITransferThreadCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer)
833{
834 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
835
836 PFNRTTHREAD pfnRTThread = NULL;
837
838 if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_READ)
839 pfnRTThread = sharedClipboardURITransferReadThread;
840 else if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_WRITE)
841 pfnRTThread = sharedClipboardURITransferWriteThread;
842
843 AssertPtrReturn(pfnRTThread, VERR_NOT_SUPPORTED);
844
845 /* Spawn a worker thread, so that we don't block the window thread for too long. */
846 int rc = RTThreadCreate(&pTransfer->Thread.hThread, pfnRTThread,
847 pTransfer /* pvUser */, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
848 "shclp");
849 if (RT_SUCCESS(rc))
850 {
851 int rc2 = RTThreadUserWait(pTransfer->Thread.hThread, 30 * 1000 /* Timeout in ms */);
852 AssertRC(rc2);
853
854 if (!pTransfer->Thread.fStarted) /* Did the thread fail to start? */
855 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
856 }
857
858 LogFlowFuncLeaveRC(rc);
859 return rc;
860}
861
862/**
863 * Destroys a thread of a clipboard URI transfer.
864 *
865 * @returns VBox status code.
866 * @param pTransfer URI clipboard transfer to destroy thread for.
867 * @param uTimeoutMs Timeout (in ms) to wait for thread creation.
868 */
869static int sharedClipboardURITransferThreadDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer, RTMSINTERVAL uTimeoutMs)
870{
871 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
872
873 if (pTransfer->Thread.hThread == NIL_RTTHREAD)
874 return VINF_SUCCESS;
875
876 int rcThread = VERR_WRONG_ORDER;
877 int rc = RTThreadWait(pTransfer->Thread.hThread, uTimeoutMs, &rcThread);
878
879 LogFlowFunc(("Waiting for thread resulted in %Rrc (thread exited with %Rrc)\n", rc, rcThread));
880
881 return rc;
882}
883
884/**
885 * Reads all URI objects using the connected provider.
886 *
887 * @returns VBox status code.
888 * @param pTransfer Transfer to read objects for.
889 */
890int SharedClipboardURITransferRead(PSHAREDCLIPBOARDURITRANSFER pTransfer)
891{
892 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
893
894 LogFlowFuncEnter();
895
896 int rc = SharedClipboardURITransferMetaDataRead(pTransfer, NULL /* pcbRead */);
897 if (RT_SUCCESS(rc))
898 {
899 rc = SharedClipboardURITransferWriteObjects(pTransfer);
900 if (RT_SUCCESS(rc))
901 {
902 if (pTransfer->Callbacks.pfnTransferComplete)
903 {
904 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
905 pTransfer->Callbacks.pfnTransferComplete(&callbackData, rc);
906 }
907 }
908 }
909
910 if (RT_FAILURE(rc))
911 {
912 if (pTransfer->Callbacks.pfnTransferError)
913 {
914 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
915 pTransfer->Callbacks.pfnTransferError(&callbackData, rc);
916 }
917 }
918
919 LogFlowFuncLeaveRC(rc);
920 return rc;
921}
922
923/**
924 * Thread for transferring (reading) URI objects from source to the target.
925 * For target to source transfers we utilize our own IDataObject / IStream implementations.
926 *
927 * @returns VBox status code.
928 * @param hThread Thread handle.
929 * @param pvUser User arguments; is PSHAREDCLIPBOARDURITRANSFER.
930 */
931static int sharedClipboardURITransferReadThread(RTTHREAD hThread, void *pvUser)
932{
933 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
934
935 LogFlowFuncEnter();
936
937 /* At the moment we only support one transfer at a time. */
938 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)pvUser;
939 AssertPtr(pTransfer->pProvider);
940
941 int rc = VINF_SUCCESS;
942
943 if (RT_SUCCESS(rc))
944 pTransfer->Thread.fStarted = true;
945
946 int rc2 = RTThreadUserSignal(hThread);
947 const bool fSignalled = RT_SUCCESS(rc2);
948
949 if (RT_SUCCESS(rc))
950 rc = SharedClipboardURITransferRead(pTransfer);
951
952 if (!fSignalled)
953 {
954 rc2 = RTThreadUserSignal(hThread);
955 AssertRC(rc2);
956 }
957
958 LogFlowFuncLeaveRC(rc);
959 return rc;
960}
961
962/**
963 * Adds meta data for a clipboard URI transfer, internal version.
964 *
965 * @returns VBox status code.
966 * @param pTransfer URI clipboard transfer to set meta data for.
967 * @param pvMeta Pointer to meta data buffer.
968 * @param cbMeta Size (in bytes) of meta data buffer.
969 */
970static int sharedClipboardURITransferMetaDataAddInternal(PSHAREDCLIPBOARDURITRANSFER pTransfer,
971 const void *pvMeta, uint32_t cbMeta)
972{
973 LogFlowFunc(("pvMeta=%p, cbMeta=%RU32\n", pvMeta, cbMeta));
974
975 int rc = SharedClipboardMetaDataAdd(&pTransfer->State.Meta, pvMeta, cbMeta);
976
977 LogFlowFuncLeaveRC(rc);
978 return rc;
979}
980
981/**
982 * Adds meta data for a clipboard URI transfer.
983 *
984 * @returns VBox status code.
985 * @param pTransfer URI clipboard transfer to set meta data for.
986 * @param pvMeta Pointer to meta data buffer.
987 * @param cbMeta Size (in bytes) of meta data buffer.
988 */
989int SharedClipboardURITransferMetaDataAdd(PSHAREDCLIPBOARDURITRANSFER pTransfer, const void *pvMeta, uint32_t cbMeta)
990{
991 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
992
993 int rc = sharedClipboardURITransferMetaDataAddInternal(pTransfer, pvMeta, cbMeta);
994
995 LogFlowFuncLeaveRC(rc);
996 return rc;
997}
998
999/**
1000 * Marks the meta data as being complete and initializes everything needed for the transfer to begin.
1001 *
1002 * @returns VBox status code.
1003 * @param pTransfer URI clipboard transfer to mark meta data complete for.
1004 */
1005int SharedClipboardURITransferMetaDataComplete(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1006{
1007 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1008
1009 LogFlowFuncEnter();
1010
1011 int rc = pTransfer->URIList.SetFromURIData(SharedClipboardMetaDataRaw(&pTransfer->State.Meta),
1012 SharedClipboardMetaDataGetUsed(&pTransfer->State.Meta),
1013 SHAREDCLIPBOARDURILIST_FLAGS_NONE);
1014 if (RT_SUCCESS(rc))
1015 {
1016 pTransfer->State.Header.cbTotal = pTransfer->URIList.GetTotalBytes();
1017 pTransfer->State.Header.cbMeta = (uint32_t)SharedClipboardMetaDataGetUsed(&pTransfer->State.Meta);
1018 pTransfer->State.Header.cObjects = pTransfer->URIList.GetTotalCount();
1019
1020 PSHAREDCLIPBOARDMETADATAFMT pMetaDataFmt = (PSHAREDCLIPBOARDMETADATAFMT)RTMemAllocZ(sizeof(SHAREDCLIPBOARDMETADATAFMT));
1021 if (pMetaDataFmt)
1022 {
1023 char *pszFmt = NULL;
1024 rc = RTStrAAppend(&pszFmt, "VBoxShClURIList");
1025 if (RT_SUCCESS(rc))
1026 {
1027 pMetaDataFmt->uVer = 1;
1028 pMetaDataFmt->pvFmt = pszFmt;
1029 pMetaDataFmt->cbFmt = (uint32_t)strlen(pszFmt) + 1 /* Include terminating zero */;
1030
1031 pTransfer->State.Header.pvMetaFmt = pMetaDataFmt;
1032 pTransfer->State.Header.cbMetaFmt = sizeof(PSHAREDCLIPBOARDMETADATAFMT) + pMetaDataFmt->cbFmt;
1033 }
1034 }
1035 else
1036 rc = VERR_NO_MEMORY;
1037
1038 if (RT_SUCCESS(rc))
1039 {
1040 /** @todo Add checksum support. */
1041
1042 if (!SharedClipboardURIDataHdrIsValid(&pTransfer->State.Header))
1043 rc = VERR_INVALID_PARAMETER;
1044 }
1045 }
1046
1047 LogFlowFuncLeaveRC(rc);
1048 return rc;
1049}
1050
1051/**
1052 * Reads meta for a clipboard URI transfer.
1053 *
1054 * @returns VBox status code.
1055 * @param pTransfer URI clipboard transfer to read meta data for.
1056 * @param pcbRead How much meta data (in bytes) was read on success.
1057 */
1058int SharedClipboardURITransferMetaDataRead(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint32_t *pcbRead)
1059{
1060 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1061
1062 /* Destroy any former meta data. */
1063 SharedClipboardMetaDataDestroy(&pTransfer->State.Meta);
1064
1065 uint32_t cbReadTotal = 0;
1066
1067 int rc = pTransfer->pProvider->ReadDataHdr(&pTransfer->State.Header);
1068 if (RT_SUCCESS(rc))
1069 {
1070 uint32_t cbMeta = _4K; /** @todo Improve. */
1071 void *pvMeta = RTMemAlloc(cbMeta);
1072
1073 if (pvMeta)
1074 {
1075 uint32_t cbMetaToRead = pTransfer->State.Header.cbMeta;
1076 while (cbMetaToRead)
1077 {
1078 uint32_t cbMetaRead;
1079 rc = pTransfer->pProvider->ReadDataChunk(&pTransfer->State.Header, pvMeta, cbMeta, &cbMetaRead);
1080 if (RT_SUCCESS(rc))
1081 rc = sharedClipboardURITransferMetaDataAddInternal(pTransfer, pvMeta, cbMeta);
1082
1083 if (RT_FAILURE(rc))
1084 break;
1085
1086 Assert(cbMetaToRead >= cbMetaRead);
1087 cbMetaToRead -= cbMetaRead;
1088
1089 cbReadTotal += cbReadTotal;
1090 }
1091
1092 RTMemFree(pvMeta);
1093
1094 if (RT_SUCCESS(rc))
1095 {
1096 if (pcbRead)
1097 *pcbRead = cbReadTotal;
1098 }
1099 }
1100 else
1101 rc = VERR_NO_MEMORY;
1102 }
1103
1104 LogFlowFuncLeaveRC(rc);
1105 return rc;
1106}
1107
1108/**
1109 * Writes the actual meta data.
1110 *
1111 * @returns IPRT status code.
1112 * @param pTransfer Transfer to write meta data for.
1113 * @param pcbWritten How much bytes were written on success. Optional.
1114 */
1115int SharedClipboardURITransferMetaDataWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint32_t *pcbWritten)
1116{
1117 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1118
1119 AssertPtr(pTransfer->pProvider);
1120
1121 uint32_t cbWrittenTotal = 0;
1122
1123 int rc = pTransfer->pProvider->WriteDataHdr(&pTransfer->State.Header);
1124 if (RT_SUCCESS(rc))
1125 {
1126 /* Sanity. */
1127 Assert(pTransfer->State.Header.cbMeta == pTransfer->State.Meta.cbUsed);
1128
1129 uint32_t cbMetaToWrite = pTransfer->State.Header.cbMeta;
1130 while (cbMetaToWrite)
1131 {
1132 uint32_t cbMetaWritten;
1133 rc = pTransfer->pProvider->WriteDataChunk(&pTransfer->State.Header, (uint8_t *)pTransfer->State.Meta.pvMeta + cbWrittenTotal,
1134 cbMetaToWrite, &cbMetaWritten, 0 /* fFlags */);
1135 if (RT_SUCCESS(rc))
1136 {
1137 cbWrittenTotal += cbMetaWritten;
1138 Assert(cbWrittenTotal <= pTransfer->State.Header.cbMeta);
1139 }
1140 }
1141
1142 if (RT_SUCCESS(rc))
1143 {
1144 if (pcbWritten)
1145 *pcbWritten = cbWrittenTotal;
1146 }
1147 }
1148
1149 LogFlowFuncLeaveRC(rc);
1150 return rc;
1151}
1152
1153/**
1154 * Writes all URI objects using the connected provider.
1155 *
1156 * @returns VBox status code.
1157 * @param pTransfer Transfer to write objects for.
1158 */
1159int SharedClipboardURITransferWriteObjects(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1160{
1161 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1162
1163 LogFlowFuncEnter();
1164
1165 int rc = VINF_SUCCESS;
1166
1167 AssertPtr(pTransfer->pProvider);
1168
1169 while (!pTransfer->URIList.IsEmpty())
1170 {
1171 SharedClipboardURIObject *pObj = pTransfer->URIList.First();
1172 AssertPtrBreakStmt(pObj, rc = VERR_INVALID_POINTER);
1173
1174 switch (pObj->GetType())
1175 {
1176 case SharedClipboardURIObject::Type_Directory:
1177 {
1178 VBOXCLIPBOARDDIRDATA dirData;
1179 RT_ZERO(dirData);
1180
1181 dirData.pszPath = RTStrDup(pObj->GetDestPathAbs().c_str());
1182 dirData.cbPath = (uint32_t)strlen(dirData.pszPath);
1183
1184 rc = pTransfer->pProvider->WriteDirectory(&dirData);
1185 break;
1186 }
1187
1188 case SharedClipboardURIObject::Type_File:
1189 {
1190 VBOXCLIPBOARDFILEHDR fileHdr;
1191 RT_ZERO(fileHdr);
1192
1193 fileHdr.pszFilePath = RTStrDup(pObj->GetDestPathAbs().c_str());
1194 fileHdr.cbFilePath = (uint32_t)strlen(fileHdr.pszFilePath);
1195 fileHdr.cbSize = pObj->GetSize();
1196 fileHdr.fFlags = 0;
1197 fileHdr.fMode = pObj->GetMode();
1198
1199 rc = pTransfer->pProvider->WriteFileHdr(&fileHdr);
1200 if (RT_FAILURE(rc))
1201 break;
1202
1203 uint32_t cbData = _4K; /** @todo Improve. */
1204 void *pvData = RTMemAlloc(cbData);
1205
1206 while (!pObj->IsComplete())
1207 {
1208 VBOXCLIPBOARDFILEDATA fileData;
1209 RT_ZERO(fileData);
1210
1211 uint32_t cbRead;
1212 rc = pObj->Read(pvData, cbData, &cbRead);
1213 if (RT_SUCCESS(rc))
1214 {
1215 fileData.pvData = pvData;
1216 fileData.cbData = cbRead;
1217
1218 uint32_t cbWritten;
1219 rc = pTransfer->pProvider->WriteFileData(&fileData, &cbWritten);
1220 }
1221
1222 if (RT_FAILURE(rc))
1223 break;
1224 }
1225 break;
1226 }
1227
1228 default:
1229 AssertFailed();
1230 break;
1231 }
1232
1233 if (RT_FAILURE(rc))
1234 break;
1235
1236 /* Only remove current object on success. */
1237 pTransfer->URIList.RemoveFirst();
1238 }
1239
1240 LogFlowFuncLeaveRC(rc);
1241 return rc;
1242}
1243
1244/**
1245 * Thread for transferring (writing) URI objects from source to the target.
1246 * For target to source transfers we utilize our own IDataObject / IStream implementations.
1247 *
1248 * @returns VBox status code.
1249 * @param hThread Thread handle.
1250 * @param pvUser User arguments; is PSHAREDCLIPBOARDURITRANSFER.
1251 */
1252static int sharedClipboardURITransferWriteThread(RTTHREAD hThread, void *pvUser)
1253{
1254 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1255
1256 LogFlowFuncEnter();
1257
1258 /* At the moment we only support one transfer at a time. */
1259 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)pvUser;
1260 AssertPtr(pTransfer->pProvider);
1261
1262 int rc = VINF_SUCCESS;
1263
1264 if (RT_SUCCESS(rc))
1265 pTransfer->Thread.fStarted = true;
1266
1267 int rc2 = RTThreadUserSignal(hThread);
1268 const bool fSignalled = RT_SUCCESS(rc2);
1269
1270 if (RT_SUCCESS(rc))
1271 rc = SharedClipboardURITransferWrite(pTransfer);
1272
1273 if (!fSignalled)
1274 {
1275 rc2 = RTThreadUserSignal(hThread);
1276 AssertRC(rc2);
1277 }
1278
1279 LogFlowFuncLeaveRC(rc);
1280 return rc;
1281}
1282
1283/**
1284 * Main function to write a clipboard URI transfer.
1285 *
1286 * @returns VBox status code.
1287 * @param pURI URI clipboard context to write.
1288 */
1289int SharedClipboardURITransferWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1290{
1291 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1292
1293 LogFlowFuncEnter();
1294
1295 int rc = SharedClipboardURITransferMetaDataWrite(pTransfer, NULL /* pcbWritten */);
1296 if (RT_SUCCESS(rc))
1297 {
1298 rc = SharedClipboardURITransferWriteObjects(pTransfer);
1299 if (RT_SUCCESS(rc))
1300 {
1301 if (pTransfer->Callbacks.pfnTransferComplete)
1302 {
1303 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1304 pTransfer->Callbacks.pfnTransferComplete(&callbackData, rc);
1305 }
1306 }
1307 }
1308
1309 if (RT_FAILURE(rc))
1310 {
1311 if (pTransfer->Callbacks.pfnTransferError)
1312 {
1313 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1314 pTransfer->Callbacks.pfnTransferError(&callbackData, rc);
1315 }
1316 }
1317
1318 LogFlowFuncLeaveRC(rc);
1319 return rc;
1320}
1321
1322/**
1323 * Initializes a clipboard URI transfer.
1324 *
1325 * @returns VBox status code.
1326 * @param pURI URI clipboard context to initialize.
1327 */
1328int SharedClipboardURICtxInit(PSHAREDCLIPBOARDURICTX pURI)
1329{
1330 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
1331
1332 LogFlowFuncEnter();
1333
1334 int rc = RTCritSectInit(&pURI->CritSect);
1335 if (RT_SUCCESS(rc))
1336 {
1337 RTListInit(&pURI->List);
1338
1339 pURI->cTransfers = 0;
1340 pURI->cMaxTransfers = 1; /* For now we only support one transfer per client at a time. */
1341
1342#ifdef DEBUG_andy
1343 pURI->cMaxTransfers = UINT32_MAX;
1344#endif
1345
1346 SharedClipboardURICtxReset(pURI);
1347 }
1348
1349 return VINF_SUCCESS;
1350}
1351
1352/**
1353 * Destroys an URI clipboard information context struct.
1354 *
1355 * @param pURI URI clipboard context to destroy.
1356 */
1357void SharedClipboardURICtxDestroy(PSHAREDCLIPBOARDURICTX pURI)
1358{
1359 AssertPtrReturnVoid(pURI);
1360
1361 RTCritSectDelete(&pURI->CritSect);
1362
1363 PSHAREDCLIPBOARDURITRANSFER pTransfer, pTransferNext;
1364 RTListForEachSafe(&pURI->List, pTransfer, pTransferNext, SHAREDCLIPBOARDURITRANSFER, Node)
1365 {
1366 SharedClipboardURITransferDestroy(pTransfer);
1367 RTListNodeRemove(&pTransfer->Node);
1368 }
1369
1370 LogFlowFuncEnter();
1371}
1372
1373/**
1374 * Resets an clipboard URI transfer.
1375 *
1376 * @param pURI URI clipboard context to reset.
1377 */
1378void SharedClipboardURICtxReset(PSHAREDCLIPBOARDURICTX pURI)
1379{
1380 AssertPtrReturnVoid(pURI);
1381
1382 LogFlowFuncEnter();
1383
1384 PSHAREDCLIPBOARDURITRANSFER pTransfer;
1385 RTListForEach(&pURI->List, pTransfer, SHAREDCLIPBOARDURITRANSFER, Node)
1386 SharedClipboardURITransferReset(pTransfer);
1387}
1388
1389/**
1390 * Adds a new URI transfer to an clipboard URI transfer.
1391 *
1392 * @returns VBox status code.
1393 * @param pURI URI clipboard context to add transfer to.
1394 * @param pTransfer Pointer to URI clipboard transfer to add.
1395 */
1396int SharedClipboardURICtxTransferAdd(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
1397{
1398 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
1399 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1400
1401 LogFlowFuncEnter();
1402
1403 if (pURI->cTransfers == pURI->cMaxTransfers)
1404 return VERR_SHCLPB_MAX_TRANSFERS_REACHED;
1405
1406 RTListAppend(&pURI->List, &pTransfer->Node);
1407 pURI->cTransfers++;
1408
1409 return VINF_SUCCESS;
1410}
1411
1412/**
1413 * Removes an URI transfer from a clipboard URI transfer.
1414 *
1415 * @returns VBox status code.
1416 * @param pURI URI clipboard context to remove transfer from.
1417 * @param pTransfer Pointer to URI clipboard transfer to remove.
1418 */
1419int SharedClipboardURICtxTransferRemove(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
1420{
1421 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
1422 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1423
1424 LogFlowFuncEnter();
1425
1426 /* Sanity. */
1427 AssertReturn(pURI->cTransfers, VERR_WRONG_ORDER);
1428
1429 int rc = SharedClipboardURITransferDestroy(pTransfer);
1430 if (RT_SUCCESS(rc))
1431 {
1432
1433 RTListNodeRemove(&pTransfer->Node);
1434 Assert(pURI->cTransfers);
1435 pURI->cTransfers--;
1436 }
1437
1438 LogFlowFuncLeaveRC(rc);
1439 return rc;
1440}
1441
1442/**
1443 * Returns a specific URI transfer, internal version.
1444 *
1445 * @returns URI transfer, or NULL if not found.
1446 * @param pURI URI clipboard context to return transfer for.
1447 * @param uIdx Index of the transfer to return.
1448 */
1449static PSHAREDCLIPBOARDURITRANSFER sharedClipboardURICtxGetTransferInternal(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
1450{
1451 AssertReturn(uIdx == 0, NULL); /* Only one transfer allowed at the moment. */
1452 return RTListGetFirst(&pURI->List, SHAREDCLIPBOARDURITRANSFER, Node);
1453}
1454
1455/**
1456 * Returns a specific URI transfer.
1457 *
1458 * @returns URI transfer, or NULL if not found.
1459 * @param pURI URI clipboard context to return transfer for.
1460 * @param uIdx Index of the transfer to return.
1461 */
1462PSHAREDCLIPBOARDURITRANSFER SharedClipboardURICtxGetTransfer(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
1463{
1464 return sharedClipboardURICtxGetTransferInternal(pURI, uIdx);
1465}
1466
1467/**
1468 * Returns the number of active URI transfers.
1469 *
1470 * @returns VBox status code.
1471 * @param pURI URI clipboard context to return number for.
1472 */
1473uint32_t SharedClipboardURICtxGetActiveTransfers(PSHAREDCLIPBOARDURICTX pURI)
1474{
1475 AssertPtrReturn(pURI, 0);
1476 return pURI->cTransfers;
1477}
1478
1479/**
1480 * Returns whether the maximum of concurrent transfers of a specific URI context has been reached or not.
1481 *
1482 * @returns \c if maximum has been reached, \c false if not.
1483 * @param pURI URI clipboard context to determine value for.
1484 */
1485bool SharedClipboardURICtxMaximumTransfersReached(PSHAREDCLIPBOARDURICTX pURI)
1486{
1487 AssertPtrReturn(pURI, true);
1488
1489 LogFlowFunc(("cTransfers=%RU32\n", pURI->cTransfers));
1490
1491 Assert(pURI->cTransfers <= pURI->cMaxTransfers);
1492 return pURI->cTransfers == pURI->cMaxTransfers;
1493}
1494#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
1495
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