VirtualBox

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

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

Shared Clipboard/URI: Build fix.

  • Property eol-style set to native
  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 45.8 KB
Line 
1/* $Id: clipboard-common.cpp 79178 2019-06-17 10:52:52Z 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 LOG_ENABLED
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
384void VBoxClipboardDbgDumpData(const void *pv, size_t cb, VBOXCLIPBOARDFORMAT u32Format)
385{
386 if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
387 {
388 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT:\n"));
389 if (pv && cb)
390 LogFunc(("%ls\n", pv));
391 else
392 LogFunc(("%p %zu\n", pv, cb));
393 }
394 else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
395 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n"));
396 else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_HTML)
397 {
398 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_HTML:\n"));
399 if (pv && cb)
400 {
401 LogFunc(("%s\n", pv));
402
403 //size_t cb = RTStrNLen(pv, );
404 char *pszBuf = (char *)RTMemAllocZ(cb + 1);
405 RTStrCopy(pszBuf, cb + 1, (const char *)pv);
406 for (size_t off = 0; off < cb; ++off)
407 {
408 if (pszBuf[off] == '\n' || pszBuf[off] == '\r')
409 pszBuf[off] = ' ';
410 }
411
412 LogFunc(("%s\n", pszBuf));
413 RTMemFree(pszBuf);
414 }
415 else
416 LogFunc(("%p %zu\n", pv, cb));
417 }
418 else
419 LogFunc(("Invalid format %02X\n", u32Format));
420}
421#endif /* LOG_ENABLED */
422
423#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
424/**
425 * Returns the size (in bytes) of the announced meta data.
426 *
427 * @returns Announced meta data size in bytes.
428 * @param pDataHdr Data header struct to get announced meta data size for.
429 */
430uint32_t SharedClipboardURIDataHdrGetMetaDataSize(PVBOXCLIPBOARDDATAHDR pDataHdr)
431{
432 AssertPtrReturn(pDataHdr, 0);
433
434 return pDataHdr->cbMeta;
435}
436
437/**
438 * Initializes an URI data header struct.
439 *
440 * @returns VBox status code.
441 * @param pDataHdr Data header struct to initialize.
442 */
443int SharedClipboardURIDataHdrInit(PVBOXCLIPBOARDDATAHDR pDataHdr)
444{
445 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
446
447 SharedClipboardURIDataHdrReset(pDataHdr);
448
449 return VINF_SUCCESS;
450}
451
452/**
453 * Destroys an URI data header struct.
454 *
455 * @param pDataHdr Data header struct to destroy.
456 */
457void SharedClipboardURIDataHdrDestroy(PVBOXCLIPBOARDDATAHDR pDataHdr)
458{
459 if (!pDataHdr)
460 return;
461
462 if (pDataHdr->pvMetaFmt)
463 {
464 Assert(pDataHdr->cbMetaFmt);
465
466 PSHAREDCLIPBOARDMETADATAFMT pMetaDatafmt = (PSHAREDCLIPBOARDMETADATAFMT)pDataHdr->pvMetaFmt;
467 AssertPtr(pMetaDatafmt);
468 if (pMetaDatafmt->pvFmt)
469 {
470 Assert(pMetaDatafmt->cbFmt);
471 RTMemFree(pMetaDatafmt->pvFmt);
472 }
473
474 RTMemFree(pDataHdr->pvMetaFmt);
475 pDataHdr->pvMetaFmt = NULL;
476 pDataHdr->cbMetaFmt = 0;
477 }
478
479 if (pDataHdr->pvChecksum)
480 {
481 Assert(pDataHdr->cbChecksum);
482
483 RTMemFree(pDataHdr->pvChecksum);
484 pDataHdr->pvChecksum = NULL;
485 pDataHdr->cbChecksum = 0;
486 }
487}
488
489/**
490 * Resets an URI data header struct.
491 *
492 * @returns VBox status code.
493 * @param pDataHdr Data header struct to reset.
494 */
495void SharedClipboardURIDataHdrReset(PVBOXCLIPBOARDDATAHDR pDataHdr)
496{
497 AssertPtrReturnVoid(pDataHdr);
498
499 LogFlowFuncEnter();
500
501 RT_BZERO(pDataHdr, sizeof(VBOXCLIPBOARDDATAHDR));
502}
503
504/**
505 * Returns whether a given clipboard data header is valid or not.
506 *
507 * @returns \c true if valid, \c false if not.
508 * @param pDataHdr Clipboard data header to validate.
509 */
510bool SharedClipboardURIDataHdrIsValid(PVBOXCLIPBOARDDATAHDR pDataHdr)
511{
512 RT_NOREF(pDataHdr);
513 return true; /** @todo Implement this. */
514}
515
516/**
517 * Returns whether a given clipboard data chunk is valid or not.
518 *
519 * @returns \c true if valid, \c false if not.
520 * @param pDataChunk Clipboard data chunk to validate.
521 */
522bool SharedClipboardURIDataChunkIsValid(PVBOXCLIPBOARDDATACHUNK pDataChunk)
523{
524 RT_NOREF(pDataChunk);
525 return true; /** @todo Implement this. */
526}
527
528/**
529 * Returns whether given clipboard directory data is valid or not.
530 *
531 * @returns \c true if valid, \c false if not.
532 * @param pDirData Clipboard directory data to validate.
533 */
534bool SharedClipboardURIDirDataIsValid(PVBOXCLIPBOARDDIRDATA pDirData)
535{
536 if ( !pDirData->cbPath
537 || pDirData->cbPath > RTPATH_MAX)
538 return false;
539
540 if (!RTStrIsValidEncoding(pDirData->pszPath))
541 return false;
542
543 return true;
544}
545
546/**
547 * Returns whether a given clipboard file header is valid or not.
548 *
549 * @returns \c true if valid, \c false if not.
550 * @param pFileHdr Clipboard file header to validate.
551 * @param pDataHdr Data header to use for validation.
552 */
553bool SharedClipboardURIFileHdrIsValid(PVBOXCLIPBOARDFILEHDR pFileHdr, PVBOXCLIPBOARDDATAHDR pDataHdr)
554{
555 if ( !pFileHdr->cbFilePath
556 || pFileHdr->cbFilePath > RTPATH_MAX)
557 return false;
558
559 if (!RTStrIsValidEncoding(pFileHdr->pszFilePath))
560 return false;
561
562 if (pFileHdr->cbSize > pDataHdr->cbTotal)
563 return false;
564
565 return true;
566}
567
568/**
569 * Returns whether given clipboard file data is valid or not.
570 *
571 * @returns \c true if valid, \c false if not.
572 * @param pFileData Clipboard file data to validate.
573 * @param pDataHdr Data header to use for validation.
574 */
575bool SharedClipboardURIFileDataIsValid(PVBOXCLIPBOARDFILEDATA pFileData, PVBOXCLIPBOARDDATAHDR pDataHdr)
576{
577 RT_NOREF(pFileData, pDataHdr);
578 return true;
579}
580
581/**
582 * Initializes an URI object context.
583 *
584 * @returns VBox status code.
585 * @param pObjCtx URI object context to initialize.
586 */
587int SharedClipboardURIObjCtxInit(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
588{
589 AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER);
590
591 LogFlowFuncEnter();
592
593 pObjCtx->pObj = NULL;
594
595 return VINF_SUCCESS;
596}
597
598/**
599 * Uninitializes an URI object context.
600 *
601 * @param pObjCtx URI object context to uninitialize.
602 */
603void SharedClipboardURIObjCtxUninit(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
604{
605 AssertPtrReturnVoid(pObjCtx);
606
607 LogFlowFuncEnter();
608
609 if (pObjCtx->pObj)
610 {
611 pObjCtx->pObj->Close();
612 delete pObjCtx->pObj;
613 }
614
615 pObjCtx->pObj = NULL;
616}
617
618/**
619 * Returns the URI object context's URI object.
620 *
621 * @returns Pointer to the URI object context's URI object.
622 * @param pObjCtx URI object context to return the URI object for.
623 */
624SharedClipboardURIObject *SharedClipboardURIObjCtxGetObj(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
625{
626 AssertPtrReturn(pObjCtx, NULL);
627 return pObjCtx->pObj;
628}
629
630/**
631 * Returns if an URI object context is valid or not.
632 *
633 * @returns \c true if valid, \c false if not.
634 * @param pObjCtx URI object context to check.
635 */
636bool SharedClipboardURIObjCtxIsValid(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
637{
638 return ( pObjCtx
639 && pObjCtx->pObj
640 && pObjCtx->pObj->IsComplete() == false
641 && pObjCtx->pObj->IsOpen());
642}
643
644/**
645 * Initializes an URI clipboard transfer struct.
646 *
647 * @returns VBox status code.
648 * @param enmDir Transfer direction.
649 * @param pCtx Shared Clipboard provider creation context to use.
650 * @param ppTransfer Where to return the created URI transfer struct.
651 * Must be destroyed by SharedClipboardURITransferDestroy().
652 */
653int SharedClipboardURITransferCreate(SHAREDCLIPBOARDURITRANSFERDIR enmDir, PSHAREDCLIPBOARDPROVIDERCREATIONCTX pCtx,
654 PSHAREDCLIPBOARDURITRANSFER *ppTransfer)
655{
656 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
657 AssertPtrReturn(ppTransfer, VERR_INVALID_POINTER);
658
659 LogFlowFuncEnter();
660
661 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)RTMemAlloc(sizeof(SHAREDCLIPBOARDURITRANSFER));
662 if (!pTransfer)
663 return VERR_NO_MEMORY;
664
665 pTransfer->State.enmDir = enmDir;
666
667 int rc = SharedClipboardURIDataHdrInit(&pTransfer->State.Header);
668 if (RT_SUCCESS(rc))
669 {
670 rc = SharedClipboardMetaDataInit(&pTransfer->State.Meta);
671 if (RT_SUCCESS(rc))
672 {
673 pTransfer->pArea = NULL; /* Will be created later if needed. */
674 pTransfer->pProvider = SharedClipboardProvider::Create(pCtx);
675 if (pTransfer->pProvider)
676 {
677 pTransfer->Thread.hThread = NIL_RTTHREAD;
678 pTransfer->Thread.fCancelled = false;
679 pTransfer->Thread.fStarted = false;
680
681 pTransfer->pvUser = NULL;
682 pTransfer->cbUser = 0;
683
684 *ppTransfer = pTransfer;
685 }
686 else
687 rc = VERR_NO_MEMORY;
688 }
689 }
690
691 LogFlowFuncLeaveRC(rc);
692 return rc;
693}
694
695/**
696 * Destroys an URI clipboard transfer context struct.
697 *
698 * @returns VBox status code.
699 * @param pURI URI clipboard transfer to destroy.
700 */
701int SharedClipboardURITransferDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer)
702{
703 if (!pTransfer)
704 return VINF_SUCCESS;
705
706 LogFlowFuncEnter();
707
708 int rc = sharedClipboardURITransferThreadDestroy(pTransfer, 30 * 1000 /* Timeout in ms */);
709 if (RT_FAILURE(rc))
710 return rc;
711
712 SharedClipboardURIDataHdrDestroy(&pTransfer->State.Header);
713 SharedClipboardMetaDataDestroy(&pTransfer->State.Meta);
714
715 if (pTransfer->pProvider)
716 {
717 delete pTransfer->pProvider;
718 pTransfer->pProvider = NULL;
719 }
720
721 RTMemFree(pTransfer);
722 pTransfer = NULL;
723
724 LogFlowFuncLeave();
725
726 return VINF_SUCCESS;
727}
728
729/**
730 * Resets an clipboard URI transfer.
731 *
732 * @param pTransfer URI clipboard transfer to reset.
733 */
734void SharedClipboardURITransferReset(PSHAREDCLIPBOARDURITRANSFER pTransfer)
735{
736 AssertPtrReturnVoid(pTransfer);
737
738 LogFlowFuncEnter();
739
740 /** @todo Anything else to do here? */
741
742 if (pTransfer->pProvider)
743 pTransfer->pProvider->Reset();
744
745 pTransfer->URIList.Clear();
746}
747
748/**
749 * Returns the clipboard area for a clipboard URI transfer.
750 *
751 * @returns Current clipboard area, or NULL if none.
752 * @param pTransfer URI clipboard transfer to return clipboard area for.
753 */
754SharedClipboardArea *SharedClipboardURITransferGetArea(PSHAREDCLIPBOARDURITRANSFER pTransfer)
755{
756 AssertPtrReturn(pTransfer, NULL);
757
758 return pTransfer->pArea;
759}
760
761/**
762 * Returns the current URI object for a clipboard URI transfer.
763 *
764 * @returns Current URI object, or NULL if none.
765 * @param pTransfer URI clipboard transfer to return current URI object for.
766 */
767const SharedClipboardURIObject *SharedClipboardURITransferGetCurrentObject(PSHAREDCLIPBOARDURITRANSFER pTransfer)
768{
769 AssertPtrReturn(pTransfer, NULL);
770
771 return pTransfer->URIList.First();
772}
773
774/**
775 * Returns the provider for a clipboard URI transfer.
776 *
777 * @returns Current provider, or NULL if none.
778 * @param pTransfer URI clipboard transfer to return provider for.
779 */
780SharedClipboardProvider *SharedClipboardURITransferGetProvider(PSHAREDCLIPBOARDURITRANSFER pTransfer)
781{
782 AssertPtrReturn(pTransfer, NULL);
783
784 return pTransfer->pProvider;
785}
786
787/**
788 * Returns the URI list for a clipboard URI transfer.
789 *
790 * @returns Pointer to URI list.
791 * @param pTransfer URI clipboard transfer to return URI list for.
792 */
793SharedClipboardURIList *SharedClipboardURITransferGetList(PSHAREDCLIPBOARDURITRANSFER pTransfer)
794{
795 return &pTransfer->URIList;
796}
797
798/**
799 * Returns the current URI object for a clipboard URI transfer.
800 *
801 * @returns Pointer to URI object.
802 * @param pTransfer URI clipboard transfer to return URI object for.
803 */
804SharedClipboardURIObject *SharedClipboardURITransferGetObject(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint64_t uIdx)
805{
806 return pTransfer->URIList.At(uIdx);
807}
808
809/**
810 * Runs (starts) an URI transfer, either in synchronous or asynchronous (threaded) mode.
811 *
812 * @returns VBox status code.
813 * @param pTransfer URI clipboard transfer to run.
814 * @param fAsync Whether to run the transfer synchronously or asynchronously.
815 */
816int SharedClipboardURITransferRun(PSHAREDCLIPBOARDURITRANSFER pTransfer, bool fAsync)
817{
818 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
819
820 int rc;
821
822 LogFlowFunc(("fAsync=%RTbool\n", fAsync));
823
824 if (fAsync)
825 {
826 rc = sharedClipboardURITransferThreadCreate(pTransfer);
827 }
828 else
829 {
830 if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_READ)
831 rc = SharedClipboardURITransferRead(pTransfer);
832 else if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_WRITE)
833 rc = SharedClipboardURITransferWrite(pTransfer);
834 else
835 rc = VERR_NOT_IMPLEMENTED;
836 }
837
838 LogFlowFuncLeaveRC(rc);
839 return rc;
840}
841
842/**
843 * Sets or unsets the callback table to be used for a clipboard URI transfer.
844 *
845 * @returns VBox status code.
846 * @param pTransfer URI clipboard transfer to set callbacks for.
847 * @param pCallbacks Pointer to callback table to set. Specify NULL to unset existing callbacks.
848 */
849void SharedClipboardURITransferSetCallbacks(PSHAREDCLIPBOARDURITRANSFER pTransfer, PSHAREDCLIPBOARDURITRANSFERCALLBACKS pCallbacks)
850{
851 AssertPtrReturnVoid(pTransfer);
852 /* pCallbacks might be NULL to unset callbacks. */
853
854 LogFlowFunc(("pCallbacks=%p\n", pCallbacks));
855
856 if (pCallbacks)
857 {
858 pTransfer->Callbacks = *pCallbacks;
859 }
860 else
861 RT_ZERO(pTransfer->Callbacks);
862}
863
864/**
865 * Creates a thread for a clipboard URI transfer.
866 *
867 * @returns VBox status code.
868 * @param pTransfer URI clipboard transfer to create thread for.
869 */
870static int sharedClipboardURITransferThreadCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer)
871{
872 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
873
874 PFNRTTHREAD pfnRTThread = NULL;
875
876 if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_READ)
877 pfnRTThread = sharedClipboardURITransferReadThread;
878 else if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_WRITE)
879 pfnRTThread = sharedClipboardURITransferWriteThread;
880
881 AssertPtrReturn(pfnRTThread, VERR_NOT_SUPPORTED);
882
883 /* Spawn a worker thread, so that we don't block the window thread for too long. */
884 int rc = RTThreadCreate(&pTransfer->Thread.hThread, pfnRTThread,
885 pTransfer /* pvUser */, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
886 "shclp");
887 if (RT_SUCCESS(rc))
888 {
889 int rc2 = RTThreadUserWait(pTransfer->Thread.hThread, 30 * 1000 /* Timeout in ms */);
890 AssertRC(rc2);
891
892 if (!pTransfer->Thread.fStarted) /* Did the thread fail to start? */
893 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
894 }
895
896 LogFlowFuncLeaveRC(rc);
897 return rc;
898}
899
900/**
901 * Destroys a thread of a clipboard URI transfer.
902 *
903 * @returns VBox status code.
904 * @param pTransfer URI clipboard transfer to destroy thread for.
905 * @param uTimeoutMs Timeout (in ms) to wait for thread creation.
906 */
907static int sharedClipboardURITransferThreadDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer, RTMSINTERVAL uTimeoutMs)
908{
909 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
910
911 if (pTransfer->Thread.hThread == NIL_RTTHREAD)
912 return VINF_SUCCESS;
913
914 int rcThread = VERR_WRONG_ORDER;
915 int rc = RTThreadWait(pTransfer->Thread.hThread, uTimeoutMs, &rcThread);
916
917 LogFlowFunc(("Waiting for thread resulted in %Rrc (thread exited with %Rrc)\n", rc, rcThread));
918
919 return rc;
920}
921
922/**
923 * Reads all URI objects using the connected provider.
924 *
925 * @returns VBox status code.
926 * @param pTransfer Transfer to read objects for.
927 */
928int SharedClipboardURITransferRead(PSHAREDCLIPBOARDURITRANSFER pTransfer)
929{
930 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
931
932 LogFlowFuncEnter();
933
934 int rc = SharedClipboardURITransferMetaDataRead(pTransfer, NULL /* pcbRead */);
935 if (RT_SUCCESS(rc))
936 {
937 rc = SharedClipboardURITransferWriteObjects(pTransfer);
938 if (RT_SUCCESS(rc))
939 {
940 if (pTransfer->Callbacks.pfnTransferComplete)
941 {
942 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
943 pTransfer->Callbacks.pfnTransferComplete(&callbackData, rc);
944 }
945 }
946 }
947
948 if (RT_FAILURE(rc))
949 {
950 if (pTransfer->Callbacks.pfnTransferError)
951 {
952 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
953 pTransfer->Callbacks.pfnTransferError(&callbackData, rc);
954 }
955 }
956
957 LogFlowFuncLeaveRC(rc);
958 return rc;
959}
960
961/**
962 * Thread for transferring (reading) URI objects from source to the target.
963 * For target to source transfers we utilize our own IDataObject / IStream implementations.
964 *
965 * @returns VBox status code.
966 * @param hThread Thread handle.
967 * @param pvUser User arguments; is PSHAREDCLIPBOARDURITRANSFER.
968 */
969static int sharedClipboardURITransferReadThread(RTTHREAD hThread, void *pvUser)
970{
971 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
972
973 LogFlowFuncEnter();
974
975 /* At the moment we only support one transfer at a time. */
976 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)pvUser;
977 AssertPtr(pTransfer->pProvider);
978
979 int rc = VINF_SUCCESS;
980
981 if (RT_SUCCESS(rc))
982 pTransfer->Thread.fStarted = true;
983
984 int rc2 = RTThreadUserSignal(hThread);
985 const bool fSignalled = RT_SUCCESS(rc2);
986
987 if (RT_SUCCESS(rc))
988 rc = SharedClipboardURITransferRead(pTransfer);
989
990 if (!fSignalled)
991 {
992 rc2 = RTThreadUserSignal(hThread);
993 AssertRC(rc2);
994 }
995
996 LogFlowFuncLeaveRC(rc);
997 return rc;
998}
999
1000/**
1001 * Adds meta data for a clipboard URI transfer, internal version.
1002 *
1003 * @returns VBox status code.
1004 * @param pTransfer URI clipboard transfer to set meta data for.
1005 * @param pvMeta Pointer to meta data buffer.
1006 * @param cbMeta Size (in bytes) of meta data buffer.
1007 */
1008static int sharedClipboardURITransferMetaDataAddInternal(PSHAREDCLIPBOARDURITRANSFER pTransfer,
1009 const void *pvMeta, uint32_t cbMeta)
1010{
1011 LogFlowFunc(("pvMeta=%p, cbMeta=%RU32\n", pvMeta, cbMeta));
1012
1013 int rc = SharedClipboardMetaDataAdd(&pTransfer->State.Meta, pvMeta, cbMeta);
1014
1015 LogFlowFuncLeaveRC(rc);
1016 return rc;
1017}
1018
1019/**
1020 * Adds meta data for a clipboard URI transfer.
1021 *
1022 * @returns VBox status code.
1023 * @param pTransfer URI clipboard transfer to set meta data for.
1024 * @param pvMeta Pointer to meta data buffer.
1025 * @param cbMeta Size (in bytes) of meta data buffer.
1026 */
1027int SharedClipboardURITransferMetaDataAdd(PSHAREDCLIPBOARDURITRANSFER pTransfer, const void *pvMeta, uint32_t cbMeta)
1028{
1029 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1030
1031 int rc = sharedClipboardURITransferMetaDataAddInternal(pTransfer, pvMeta, cbMeta);
1032
1033 LogFlowFuncLeaveRC(rc);
1034 return rc;
1035}
1036
1037/**
1038 * Marks the meta data as being complete and initializes everything needed for the transfer to begin.
1039 *
1040 * @returns VBox status code.
1041 * @param pTransfer URI clipboard transfer to mark meta data complete for.
1042 */
1043int SharedClipboardURITransferMetaDataComplete(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1044{
1045 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1046
1047 LogFlowFuncEnter();
1048
1049 int rc = pTransfer->URIList.SetFromURIData(SharedClipboardMetaDataRaw(&pTransfer->State.Meta),
1050 SharedClipboardMetaDataGetUsed(&pTransfer->State.Meta),
1051 SHAREDCLIPBOARDURILIST_FLAGS_NONE);
1052 if (RT_SUCCESS(rc))
1053 {
1054 pTransfer->State.Header.cbTotal = pTransfer->URIList.GetTotalBytes();
1055 pTransfer->State.Header.cbMeta = (uint32_t)SharedClipboardMetaDataGetUsed(&pTransfer->State.Meta);
1056 pTransfer->State.Header.cObjects = pTransfer->URIList.GetTotalCount();
1057
1058 PSHAREDCLIPBOARDMETADATAFMT pMetaDataFmt = (PSHAREDCLIPBOARDMETADATAFMT)RTMemAllocZ(sizeof(SHAREDCLIPBOARDMETADATAFMT));
1059 if (pMetaDataFmt)
1060 {
1061 char *pszFmt = NULL;
1062 rc = RTStrAAppend(&pszFmt, "VBoxShClURIList");
1063 if (RT_SUCCESS(rc))
1064 {
1065 pMetaDataFmt->uVer = 1;
1066 pMetaDataFmt->pvFmt = pszFmt;
1067 pMetaDataFmt->cbFmt = (uint32_t)strlen(pszFmt) + 1 /* Include terminating zero */;
1068
1069 pTransfer->State.Header.pvMetaFmt = pMetaDataFmt;
1070 pTransfer->State.Header.cbMetaFmt = sizeof(PSHAREDCLIPBOARDMETADATAFMT) + pMetaDataFmt->cbFmt;
1071 }
1072 }
1073 else
1074 rc = VERR_NO_MEMORY;
1075
1076 if (RT_SUCCESS(rc))
1077 {
1078 /** @todo Add checksum support. */
1079
1080 if (!SharedClipboardURIDataHdrIsValid(&pTransfer->State.Header))
1081 rc = VERR_INVALID_PARAMETER;
1082 }
1083 }
1084
1085 LogFlowFuncLeaveRC(rc);
1086 return rc;
1087}
1088
1089/**
1090 * Reads meta for a clipboard URI transfer.
1091 *
1092 * @returns VBox status code.
1093 * @param pTransfer URI clipboard transfer to read meta data for.
1094 * @param pcbRead How much meta data (in bytes) was read on success.
1095 */
1096int SharedClipboardURITransferMetaDataRead(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint32_t *pcbRead)
1097{
1098 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1099
1100 /* Destroy any former meta data. */
1101 SharedClipboardMetaDataDestroy(&pTransfer->State.Meta);
1102
1103 uint32_t cbReadTotal = 0;
1104
1105 int rc = pTransfer->pProvider->ReadDataHdr(&pTransfer->State.Header);
1106 if (RT_SUCCESS(rc))
1107 {
1108 uint32_t cbMeta = _4K; /** @todo Improve. */
1109 void *pvMeta = RTMemAlloc(cbMeta);
1110
1111 if (pvMeta)
1112 {
1113 uint32_t cbMetaToRead = pTransfer->State.Header.cbMeta;
1114 while (cbMetaToRead)
1115 {
1116 uint32_t cbMetaRead;
1117 rc = pTransfer->pProvider->ReadDataChunk(&pTransfer->State.Header, pvMeta, cbMeta, &cbMetaRead);
1118 if (RT_SUCCESS(rc))
1119 rc = sharedClipboardURITransferMetaDataAddInternal(pTransfer, pvMeta, cbMeta);
1120
1121 if (RT_FAILURE(rc))
1122 break;
1123
1124 Assert(cbMetaToRead >= cbMetaRead);
1125 cbMetaToRead -= cbMetaRead;
1126
1127 cbReadTotal += cbReadTotal;
1128 }
1129
1130 RTMemFree(pvMeta);
1131
1132 if (RT_SUCCESS(rc))
1133 {
1134 if (pcbRead)
1135 *pcbRead = cbReadTotal;
1136 }
1137 }
1138 else
1139 rc = VERR_NO_MEMORY;
1140 }
1141
1142 LogFlowFuncLeaveRC(rc);
1143 return rc;
1144}
1145
1146/**
1147 * Writes the actual meta data.
1148 *
1149 * @returns IPRT status code.
1150 * @param pTransfer Transfer to write meta data for.
1151 * @param pcbWritten How much bytes were written on success. Optional.
1152 */
1153int SharedClipboardURITransferMetaDataWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint32_t *pcbWritten)
1154{
1155 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1156
1157 AssertPtr(pTransfer->pProvider);
1158
1159 uint32_t cbWrittenTotal = 0;
1160
1161 int rc = pTransfer->pProvider->WriteDataHdr(&pTransfer->State.Header);
1162 if (RT_SUCCESS(rc))
1163 {
1164 /* Sanity. */
1165 Assert(pTransfer->State.Header.cbMeta == pTransfer->State.Meta.cbUsed);
1166
1167 uint32_t cbMetaToWrite = pTransfer->State.Header.cbMeta;
1168 while (cbMetaToWrite)
1169 {
1170 uint32_t cbMetaWritten;
1171 rc = pTransfer->pProvider->WriteDataChunk(&pTransfer->State.Header, (uint8_t *)pTransfer->State.Meta.pvMeta + cbWrittenTotal,
1172 cbMetaToWrite, &cbMetaWritten, 0 /* fFlags */);
1173 if (RT_SUCCESS(rc))
1174 {
1175 cbWrittenTotal += cbMetaWritten;
1176 Assert(cbWrittenTotal <= pTransfer->State.Header.cbMeta);
1177 }
1178 }
1179
1180 if (RT_SUCCESS(rc))
1181 {
1182 if (pcbWritten)
1183 *pcbWritten = cbWrittenTotal;
1184 }
1185 }
1186
1187 LogFlowFuncLeaveRC(rc);
1188 return rc;
1189}
1190
1191/**
1192 * Writes all URI objects using the connected provider.
1193 *
1194 * @returns VBox status code.
1195 * @param pTransfer Transfer to write objects for.
1196 */
1197int SharedClipboardURITransferWriteObjects(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1198{
1199 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1200
1201 LogFlowFuncEnter();
1202
1203 int rc = VINF_SUCCESS;
1204
1205 AssertPtr(pTransfer->pProvider);
1206
1207 while (!pTransfer->URIList.IsEmpty())
1208 {
1209 SharedClipboardURIObject *pObj = pTransfer->URIList.First();
1210 AssertPtrBreakStmt(pObj, rc = VERR_INVALID_POINTER);
1211
1212 switch (pObj->GetType())
1213 {
1214 case SharedClipboardURIObject::Type_Directory:
1215 {
1216 VBOXCLIPBOARDDIRDATA dirData;
1217 RT_ZERO(dirData);
1218
1219 dirData.pszPath = RTStrDup(pObj->GetDestPathAbs().c_str());
1220 dirData.cbPath = (uint32_t)strlen(dirData.pszPath);
1221
1222 rc = pTransfer->pProvider->WriteDirectory(&dirData);
1223 break;
1224 }
1225
1226 case SharedClipboardURIObject::Type_File:
1227 {
1228 VBOXCLIPBOARDFILEHDR fileHdr;
1229 RT_ZERO(fileHdr);
1230
1231 fileHdr.pszFilePath = RTStrDup(pObj->GetDestPathAbs().c_str());
1232 fileHdr.cbFilePath = (uint32_t)strlen(fileHdr.pszFilePath);
1233 fileHdr.cbSize = pObj->GetSize();
1234 fileHdr.fFlags = 0;
1235 fileHdr.fMode = pObj->GetMode();
1236
1237 rc = pTransfer->pProvider->WriteFileHdr(&fileHdr);
1238 if (RT_FAILURE(rc))
1239 break;
1240
1241 uint32_t cbData = _4K; /** @todo Improve. */
1242 void *pvData = RTMemAlloc(cbData);
1243
1244 while (!pObj->IsComplete())
1245 {
1246 VBOXCLIPBOARDFILEDATA fileData;
1247 RT_ZERO(fileData);
1248
1249 uint32_t cbRead;
1250 rc = pObj->Read(pvData, cbData, &cbRead);
1251 if (RT_SUCCESS(rc))
1252 {
1253 fileData.pvData = pvData;
1254 fileData.cbData = cbRead;
1255
1256 uint32_t cbWritten;
1257 rc = pTransfer->pProvider->WriteFileData(&fileData, &cbWritten);
1258 }
1259
1260 if (RT_FAILURE(rc))
1261 break;
1262 }
1263 break;
1264 }
1265
1266 default:
1267 AssertFailed();
1268 break;
1269 }
1270
1271 if (RT_FAILURE(rc))
1272 break;
1273
1274 /* Only remove current object on success. */
1275 pTransfer->URIList.RemoveFirst();
1276 }
1277
1278 LogFlowFuncLeaveRC(rc);
1279 return rc;
1280}
1281
1282/**
1283 * Thread for transferring (writing) URI objects from source to the target.
1284 * For target to source transfers we utilize our own IDataObject / IStream implementations.
1285 *
1286 * @returns VBox status code.
1287 * @param hThread Thread handle.
1288 * @param pvUser User arguments; is PSHAREDCLIPBOARDURITRANSFER.
1289 */
1290static int sharedClipboardURITransferWriteThread(RTTHREAD hThread, void *pvUser)
1291{
1292 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1293
1294 LogFlowFuncEnter();
1295
1296 /* At the moment we only support one transfer at a time. */
1297 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)pvUser;
1298 AssertPtr(pTransfer->pProvider);
1299
1300 int rc = VINF_SUCCESS;
1301
1302 if (RT_SUCCESS(rc))
1303 pTransfer->Thread.fStarted = true;
1304
1305 int rc2 = RTThreadUserSignal(hThread);
1306 const bool fSignalled = RT_SUCCESS(rc2);
1307
1308 if (RT_SUCCESS(rc))
1309 rc = SharedClipboardURITransferWrite(pTransfer);
1310
1311 if (!fSignalled)
1312 {
1313 rc2 = RTThreadUserSignal(hThread);
1314 AssertRC(rc2);
1315 }
1316
1317 LogFlowFuncLeaveRC(rc);
1318 return rc;
1319}
1320
1321/**
1322 * Main function to write a clipboard URI transfer.
1323 *
1324 * @returns VBox status code.
1325 * @param pURI URI clipboard context to write.
1326 */
1327int SharedClipboardURITransferWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1328{
1329 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1330
1331 LogFlowFuncEnter();
1332
1333 int rc = SharedClipboardURITransferMetaDataWrite(pTransfer, NULL /* pcbWritten */);
1334 if (RT_SUCCESS(rc))
1335 {
1336 rc = SharedClipboardURITransferWriteObjects(pTransfer);
1337 if (RT_SUCCESS(rc))
1338 {
1339 if (pTransfer->Callbacks.pfnTransferComplete)
1340 {
1341 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1342 pTransfer->Callbacks.pfnTransferComplete(&callbackData, rc);
1343 }
1344 }
1345 }
1346
1347 if (RT_FAILURE(rc))
1348 {
1349 if (pTransfer->Callbacks.pfnTransferError)
1350 {
1351 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1352 pTransfer->Callbacks.pfnTransferError(&callbackData, rc);
1353 }
1354 }
1355
1356 LogFlowFuncLeaveRC(rc);
1357 return rc;
1358}
1359
1360/**
1361 * Initializes a clipboard URI transfer.
1362 *
1363 * @returns VBox status code.
1364 * @param pURI URI clipboard context to initialize.
1365 */
1366int SharedClipboardURICtxInit(PSHAREDCLIPBOARDURICTX pURI)
1367{
1368 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
1369
1370 LogFlowFuncEnter();
1371
1372 int rc = RTCritSectInit(&pURI->CritSect);
1373 if (RT_SUCCESS(rc))
1374 {
1375 RTListInit(&pURI->List);
1376
1377 pURI->cTransfers = 0;
1378 pURI->cMaxTransfers = 1; /* For now we only support one transfer per client at a time. */
1379
1380#ifdef DEBUG_andy
1381 pURI->cMaxTransfers = UINT32_MAX;
1382#endif
1383
1384 SharedClipboardURICtxReset(pURI);
1385 }
1386
1387 return VINF_SUCCESS;
1388}
1389
1390/**
1391 * Destroys an URI clipboard information context struct.
1392 *
1393 * @param pURI URI clipboard context to destroy.
1394 */
1395void SharedClipboardURICtxDestroy(PSHAREDCLIPBOARDURICTX pURI)
1396{
1397 AssertPtrReturnVoid(pURI);
1398
1399 RTCritSectDelete(&pURI->CritSect);
1400
1401 PSHAREDCLIPBOARDURITRANSFER pTransfer, pTransferNext;
1402 RTListForEachSafe(&pURI->List, pTransfer, pTransferNext, SHAREDCLIPBOARDURITRANSFER, Node)
1403 {
1404 SharedClipboardURITransferDestroy(pTransfer);
1405 RTListNodeRemove(&pTransfer->Node);
1406 }
1407
1408 LogFlowFuncEnter();
1409}
1410
1411/**
1412 * Resets an clipboard URI transfer.
1413 *
1414 * @param pURI URI clipboard context to reset.
1415 */
1416void SharedClipboardURICtxReset(PSHAREDCLIPBOARDURICTX pURI)
1417{
1418 AssertPtrReturnVoid(pURI);
1419
1420 LogFlowFuncEnter();
1421
1422 PSHAREDCLIPBOARDURITRANSFER pTransfer;
1423 RTListForEach(&pURI->List, pTransfer, SHAREDCLIPBOARDURITRANSFER, Node)
1424 SharedClipboardURITransferReset(pTransfer);
1425}
1426
1427/**
1428 * Adds a new URI transfer to an clipboard URI transfer.
1429 *
1430 * @returns VBox status code.
1431 * @param pURI URI clipboard context to add transfer to.
1432 * @param pTransfer Pointer to URI clipboard transfer to add.
1433 */
1434int SharedClipboardURICtxTransferAdd(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
1435{
1436 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
1437 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1438
1439 LogFlowFuncEnter();
1440
1441 if (pURI->cTransfers == pURI->cMaxTransfers)
1442 return VERR_SHCLPB_MAX_TRANSFERS_REACHED;
1443
1444 RTListAppend(&pURI->List, &pTransfer->Node);
1445 pURI->cTransfers++;
1446
1447 return VINF_SUCCESS;
1448}
1449
1450/**
1451 * Removes an URI transfer from a clipboard URI transfer.
1452 *
1453 * @returns VBox status code.
1454 * @param pURI URI clipboard context to remove transfer from.
1455 * @param pTransfer Pointer to URI clipboard transfer to remove.
1456 */
1457int SharedClipboardURICtxTransferRemove(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
1458{
1459 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
1460 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1461
1462 LogFlowFuncEnter();
1463
1464 /* Sanity. */
1465 AssertReturn(pURI->cTransfers, VERR_WRONG_ORDER);
1466
1467 int rc = SharedClipboardURITransferDestroy(pTransfer);
1468 if (RT_SUCCESS(rc))
1469 {
1470
1471 RTListNodeRemove(&pTransfer->Node);
1472 Assert(pURI->cTransfers);
1473 pURI->cTransfers--;
1474 }
1475
1476 LogFlowFuncLeaveRC(rc);
1477 return rc;
1478}
1479
1480/**
1481 * Returns a specific URI transfer, internal version.
1482 *
1483 * @returns URI transfer, or NULL if not found.
1484 * @param pURI URI clipboard context to return transfer for.
1485 * @param uIdx Index of the transfer to return.
1486 */
1487static PSHAREDCLIPBOARDURITRANSFER sharedClipboardURICtxGetTransferInternal(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
1488{
1489 AssertReturn(uIdx == 0, NULL); /* Only one transfer allowed at the moment. */
1490 return RTListGetFirst(&pURI->List, SHAREDCLIPBOARDURITRANSFER, Node);
1491}
1492
1493/**
1494 * Returns a specific URI transfer.
1495 *
1496 * @returns URI transfer, or NULL if not found.
1497 * @param pURI URI clipboard context to return transfer for.
1498 * @param uIdx Index of the transfer to return.
1499 */
1500PSHAREDCLIPBOARDURITRANSFER SharedClipboardURICtxGetTransfer(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
1501{
1502 return sharedClipboardURICtxGetTransferInternal(pURI, uIdx);
1503}
1504
1505/**
1506 * Returns the number of active URI transfers.
1507 *
1508 * @returns VBox status code.
1509 * @param pURI URI clipboard context to return number for.
1510 */
1511uint32_t SharedClipboardURICtxGetActiveTransfers(PSHAREDCLIPBOARDURICTX pURI)
1512{
1513 AssertPtrReturn(pURI, 0);
1514 return pURI->cTransfers;
1515}
1516
1517/**
1518 * Returns whether the maximum of concurrent transfers of a specific URI context has been reached or not.
1519 *
1520 * @returns \c if maximum has been reached, \c false if not.
1521 * @param pURI URI clipboard context to determine value for.
1522 */
1523bool SharedClipboardURICtxMaximumTransfersReached(PSHAREDCLIPBOARDURICTX pURI)
1524{
1525 AssertPtrReturn(pURI, true);
1526
1527 LogFlowFunc(("cTransfers=%RU32\n", pURI->cTransfers));
1528
1529 Assert(pURI->cTransfers <= pURI->cMaxTransfers);
1530 return pURI->cTransfers == pURI->cMaxTransfers;
1531}
1532#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
1533
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