VirtualBox

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

Last change on this file since 79267 was 79267, checked in by vboxsync, 5 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: 60.6 KB
Line 
1/* $Id: clipboard-common.cpp 79267 2019-06-21 10:11:59Z 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
41static void sharedClipboardURITransferMetaDataDestroyInternal(PSHAREDCLIPBOARDURITRANSFER pTransfer);
42#endif
43
44
45/** @todo use const where appropriate; delinuxify the code (*Lin* -> *Host*); use AssertLogRel*. */
46
47int vboxClipboardUtf16GetWinSize(PRTUTF16 pwszSrc, size_t cwSrc, size_t *pcwDest)
48{
49 size_t cwDest, i;
50
51 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
52 AssertLogRelMsgReturn(pwszSrc != NULL, ("vboxClipboardUtf16GetWinSize: received a null Utf16 string, returning VERR_INVALID_PARAMETER\n"), VERR_INVALID_PARAMETER);
53 if (cwSrc == 0)
54 {
55 *pcwDest = 0;
56 LogFlowFunc(("empty source string, returning\n"));
57 return VINF_SUCCESS;
58 }
59/** @todo convert the remainder of the Assert stuff to AssertLogRel. */
60 /* We only take little endian Utf16 */
61 if (pwszSrc[0] == UTF16BEMARKER)
62 {
63 LogRel(("vboxClipboardUtf16GetWinSize: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
64 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
65 }
66 cwDest = 0;
67 /* Calculate the size of the destination text string. */
68 /* Is this Utf16 or Utf16-LE? */
69 for (i = (pwszSrc[0] == UTF16LEMARKER ? 1 : 0); i < cwSrc; ++i, ++cwDest)
70 {
71 /* Check for a single line feed */
72 if (pwszSrc[i] == LINEFEED)
73 ++cwDest;
74#ifdef RT_OS_DARWIN
75 /* Check for a single carriage return (MacOS) */
76 if (pwszSrc[i] == CARRIAGERETURN)
77 ++cwDest;
78#endif
79 if (pwszSrc[i] == 0)
80 {
81 /* Don't count this, as we do so below. */
82 break;
83 }
84 }
85 /* Count the terminating null byte. */
86 ++cwDest;
87 LogFlowFunc(("returning VINF_SUCCESS, %d 16bit words\n", cwDest));
88 *pcwDest = cwDest;
89 return VINF_SUCCESS;
90}
91
92int vboxClipboardUtf16LinToWin(PRTUTF16 pwszSrc, size_t cwSrc, PRTUTF16 pu16Dest,
93 size_t cwDest)
94{
95 size_t i, j;
96 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
97 if (!VALID_PTR(pwszSrc) || !VALID_PTR(pu16Dest))
98 {
99 LogRel(("vboxClipboardUtf16LinToWin: received an invalid pointer, pwszSrc=%p, pu16Dest=%p, returning VERR_INVALID_PARAMETER\n", pwszSrc, pu16Dest));
100 AssertReturn(VALID_PTR(pwszSrc) && VALID_PTR(pu16Dest), VERR_INVALID_PARAMETER);
101 }
102 if (cwSrc == 0)
103 {
104 if (cwDest == 0)
105 {
106 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
107 return VERR_BUFFER_OVERFLOW;
108 }
109 pu16Dest[0] = 0;
110 LogFlowFunc(("empty source string, returning\n"));
111 return VINF_SUCCESS;
112 }
113 /* We only take little endian Utf16 */
114 if (pwszSrc[0] == UTF16BEMARKER)
115 {
116 LogRel(("vboxClipboardUtf16LinToWin: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
117 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
118 }
119 /* Don't copy the endian marker. */
120 for (i = (pwszSrc[0] == UTF16LEMARKER ? 1 : 0), j = 0; i < cwSrc; ++i, ++j)
121 {
122 /* Don't copy the null byte, as we add it below. */
123 if (pwszSrc[i] == 0)
124 break;
125 if (j == cwDest)
126 {
127 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
128 return VERR_BUFFER_OVERFLOW;
129 }
130 if (pwszSrc[i] == LINEFEED)
131 {
132 pu16Dest[j] = CARRIAGERETURN;
133 ++j;
134 if (j == cwDest)
135 {
136 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
137 return VERR_BUFFER_OVERFLOW;
138 }
139 }
140#ifdef RT_OS_DARWIN
141 /* Check for a single carriage return (MacOS) */
142 else if (pwszSrc[i] == CARRIAGERETURN)
143 {
144 /* set cr */
145 pu16Dest[j] = CARRIAGERETURN;
146 ++j;
147 if (j == cwDest)
148 {
149 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
150 return VERR_BUFFER_OVERFLOW;
151 }
152 /* add the lf */
153 pu16Dest[j] = LINEFEED;
154 continue;
155 }
156#endif
157 pu16Dest[j] = pwszSrc[i];
158 }
159 /* Add the trailing null. */
160 if (j == cwDest)
161 {
162 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
163 return VERR_BUFFER_OVERFLOW;
164 }
165 pu16Dest[j] = 0;
166 LogFlowFunc(("rc=VINF_SUCCESS, pu16Dest=%ls\n", pu16Dest));
167 return VINF_SUCCESS;
168}
169
170int vboxClipboardUtf16GetLinSize(PRTUTF16 pwszSrc, size_t cwSrc, size_t *pcwDest)
171{
172 size_t cwDest;
173
174 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
175 if (!VALID_PTR(pwszSrc))
176 {
177 LogRel(("vboxClipboardUtf16GetLinSize: received an invalid Utf16 string %p. Returning VERR_INVALID_PARAMETER.\n", pwszSrc));
178 AssertReturn(VALID_PTR(pwszSrc), VERR_INVALID_PARAMETER);
179 }
180 if (cwSrc == 0)
181 {
182 LogFlowFunc(("empty source string, returning VINF_SUCCESS\n"));
183 *pcwDest = 0;
184 return VINF_SUCCESS;
185 }
186 /* We only take little endian Utf16 */
187 if (pwszSrc[0] == UTF16BEMARKER)
188 {
189 LogRel(("vboxClipboardUtf16GetLinSize: received a big endian Utf16 string. Returning VERR_INVALID_PARAMETER.\n"));
190 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
191 }
192 /* Calculate the size of the destination text string. */
193 /* Is this Utf16 or Utf16-LE? */
194 if (pwszSrc[0] == UTF16LEMARKER)
195 cwDest = 0;
196 else
197 cwDest = 1;
198 for (size_t i = 0; i < cwSrc; ++i, ++cwDest)
199 {
200 if ( (i + 1 < cwSrc)
201 && (pwszSrc[i] == CARRIAGERETURN)
202 && (pwszSrc[i + 1] == LINEFEED))
203 {
204 ++i;
205 }
206 if (pwszSrc[i] == 0)
207 {
208 break;
209 }
210 }
211 /* Terminating zero */
212 ++cwDest;
213 LogFlowFunc(("returning %d\n", cwDest));
214 *pcwDest = cwDest;
215 return VINF_SUCCESS;
216}
217
218int vboxClipboardUtf16WinToLin(PRTUTF16 pwszSrc, size_t cwSrc, PRTUTF16 pu16Dest,
219 size_t cwDest)
220{
221 size_t cwDestPos;
222
223 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u, pu16Dest=%p, cwDest=%u\n",
224 cwSrc, pwszSrc, cwSrc, pu16Dest, cwDest));
225 /* A buffer of size 0 may not be an error, but it is not a good idea either. */
226 Assert(cwDest > 0);
227 if (!VALID_PTR(pwszSrc) || !VALID_PTR(pu16Dest))
228 {
229 LogRel(("vboxClipboardUtf16WinToLin: received an invalid ptr, pwszSrc=%p, pu16Dest=%p, returning VERR_INVALID_PARAMETER\n", pwszSrc, pu16Dest));
230 AssertReturn(VALID_PTR(pwszSrc) && VALID_PTR(pu16Dest), VERR_INVALID_PARAMETER);
231 }
232 /* We only take little endian Utf16 */
233 if (pwszSrc[0] == UTF16BEMARKER)
234 {
235 LogRel(("vboxClipboardUtf16WinToLin: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
236 AssertMsgFailedReturn(("received a big endian string\n"), VERR_INVALID_PARAMETER);
237 }
238 if (cwDest == 0)
239 {
240 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
241 return VERR_BUFFER_OVERFLOW;
242 }
243 if (cwSrc == 0)
244 {
245 pu16Dest[0] = 0;
246 LogFlowFunc(("received empty string. Returning VINF_SUCCESS\n"));
247 return VINF_SUCCESS;
248 }
249 /* Prepend the Utf16 byte order marker if it is missing. */
250 if (pwszSrc[0] == UTF16LEMARKER)
251 {
252 cwDestPos = 0;
253 }
254 else
255 {
256 pu16Dest[0] = UTF16LEMARKER;
257 cwDestPos = 1;
258 }
259 for (size_t i = 0; i < cwSrc; ++i, ++cwDestPos)
260 {
261 if (pwszSrc[i] == 0)
262 {
263 break;
264 }
265 if (cwDestPos == cwDest)
266 {
267 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
268 return VERR_BUFFER_OVERFLOW;
269 }
270 if ( (i + 1 < cwSrc)
271 && (pwszSrc[i] == CARRIAGERETURN)
272 && (pwszSrc[i + 1] == LINEFEED))
273 {
274 ++i;
275 }
276 pu16Dest[cwDestPos] = pwszSrc[i];
277 }
278 /* Terminating zero */
279 if (cwDestPos == cwDest)
280 {
281 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
282 return VERR_BUFFER_OVERFLOW;
283 }
284 pu16Dest[cwDestPos] = 0;
285 LogFlowFunc(("set string %ls. Returning\n", pu16Dest + 1));
286 return VINF_SUCCESS;
287}
288
289int vboxClipboardDibToBmp(const void *pvSrc, size_t cbSrc, void **ppvDest, size_t *pcbDest)
290{
291 size_t cb = sizeof(BMFILEHEADER) + cbSrc;
292 PBMFILEHEADER pFileHeader = NULL;
293 void *pvDest = NULL;
294 size_t offPixel = 0;
295
296 AssertPtrReturn(pvSrc, VERR_INVALID_PARAMETER);
297 AssertPtrReturn(ppvDest, VERR_INVALID_PARAMETER);
298 AssertPtrReturn(pcbDest, VERR_INVALID_PARAMETER);
299
300 PBMINFOHEADER pBitmapInfoHeader = (PBMINFOHEADER)pvSrc;
301 /** @todo Support all the many versions of the DIB headers. */
302 if ( cbSrc < sizeof(BMINFOHEADER)
303 || RT_LE2H_U32(pBitmapInfoHeader->u32Size) < sizeof(BMINFOHEADER)
304 || RT_LE2H_U32(pBitmapInfoHeader->u32Size) != sizeof(BMINFOHEADER))
305 {
306 Log(("vboxClipboardDibToBmp: invalid or unsupported bitmap data.\n"));
307 return VERR_INVALID_PARAMETER;
308 }
309
310 offPixel = sizeof(BMFILEHEADER)
311 + RT_LE2H_U32(pBitmapInfoHeader->u32Size)
312 + RT_LE2H_U32(pBitmapInfoHeader->u32ClrUsed) * sizeof(uint32_t);
313 if (cbSrc < offPixel)
314 {
315 Log(("vboxClipboardDibToBmp: invalid bitmap data.\n"));
316 return VERR_INVALID_PARAMETER;
317 }
318
319 pvDest = RTMemAlloc(cb);
320 if (!pvDest)
321 {
322 Log(("writeToPasteboard: cannot allocate memory for bitmap.\n"));
323 return VERR_NO_MEMORY;
324 }
325
326 pFileHeader = (PBMFILEHEADER)pvDest;
327 pFileHeader->u16Type = BITMAPHEADERMAGIC;
328 pFileHeader->u32Size = (uint32_t)RT_H2LE_U32(cb);
329 pFileHeader->u16Reserved1 = pFileHeader->u16Reserved2 = 0;
330 pFileHeader->u32OffBits = (uint32_t)RT_H2LE_U32(offPixel);
331 memcpy((uint8_t *)pvDest + sizeof(BMFILEHEADER), pvSrc, cbSrc);
332 *ppvDest = pvDest;
333 *pcbDest = cb;
334 return VINF_SUCCESS;
335}
336
337int vboxClipboardBmpGetDib(const void *pvSrc, size_t cbSrc, const void **ppvDest, size_t *pcbDest)
338{
339 AssertPtrReturn(pvSrc, VERR_INVALID_PARAMETER);
340 AssertPtrReturn(ppvDest, VERR_INVALID_PARAMETER);
341 AssertPtrReturn(pcbDest, VERR_INVALID_PARAMETER);
342
343 PBMFILEHEADER pFileHeader = (PBMFILEHEADER)pvSrc;
344 if ( cbSrc < sizeof(BMFILEHEADER)
345 || pFileHeader->u16Type != BITMAPHEADERMAGIC
346 || RT_LE2H_U32(pFileHeader->u32Size) != cbSrc)
347 {
348 Log(("vboxClipboardBmpGetDib: invalid bitmap data.\n"));
349 return VERR_INVALID_PARAMETER;
350 }
351
352 *ppvDest = ((uint8_t *)pvSrc) + sizeof(BMFILEHEADER);
353 *pcbDest = cbSrc - sizeof(BMFILEHEADER);
354 return VINF_SUCCESS;
355}
356
357#ifdef LOG_ENABLED
358int VBoxClipboardDbgDumpHtml(const char *pszSrc, size_t cbSrc)
359{
360 size_t cchIgnored = 0;
361 int rc = RTStrNLenEx(pszSrc, cbSrc, &cchIgnored);
362 if (RT_SUCCESS(rc))
363 {
364 char *pszBuf = (char *)RTMemAllocZ(cbSrc + 1);
365 if (pszBuf)
366 {
367 rc = RTStrCopy(pszBuf, cbSrc + 1, (const char *)pszSrc);
368 if (RT_SUCCESS(rc))
369 {
370 for (size_t i = 0; i < cbSrc; ++i)
371 if (pszBuf[i] == '\n' || pszBuf[i] == '\r')
372 pszBuf[i] = ' ';
373 }
374 else
375 LogFunc(("Error in copying string\n"));
376 LogFunc(("Removed \\r\\n: %s\n", pszBuf));
377 RTMemFree(pszBuf);
378 }
379 else
380 rc = VERR_NO_MEMORY;
381 }
382
383 return rc;
384}
385
386void VBoxClipboardDbgDumpData(const void *pv, size_t cb, VBOXCLIPBOARDFORMAT u32Format)
387{
388 if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
389 {
390 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT:\n"));
391 if (pv && cb)
392 LogFunc(("%ls\n", pv));
393 else
394 LogFunc(("%p %zu\n", pv, cb));
395 }
396 else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
397 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n"));
398 else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_HTML)
399 {
400 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_HTML:\n"));
401 if (pv && cb)
402 {
403 LogFunc(("%s\n", pv));
404
405 //size_t cb = RTStrNLen(pv, );
406 char *pszBuf = (char *)RTMemAllocZ(cb + 1);
407 RTStrCopy(pszBuf, cb + 1, (const char *)pv);
408 for (size_t off = 0; off < cb; ++off)
409 {
410 if (pszBuf[off] == '\n' || pszBuf[off] == '\r')
411 pszBuf[off] = ' ';
412 }
413
414 LogFunc(("%s\n", pszBuf));
415 RTMemFree(pszBuf);
416 }
417 else
418 LogFunc(("%p %zu\n", pv, cb));
419 }
420 else
421 LogFunc(("Invalid format %02X\n", u32Format));
422}
423#endif /* LOG_ENABLED */
424
425#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
426int SharedClipboardURIDataHdrAlloc(PVBOXCLIPBOARDDATAHDR *ppDataHdr)
427{
428 int rc;
429
430 PVBOXCLIPBOARDDATAHDR pDataHdr = (PVBOXCLIPBOARDDATAHDR)RTMemAllocZ(sizeof(VBOXCLIPBOARDDATAHDR));
431 if (pDataHdr)
432 {
433 PSHAREDCLIPBOARDMETADATAFMTDATA pMetaDataFmt
434 = (PSHAREDCLIPBOARDMETADATAFMTDATA)RTMemAllocZ(sizeof(SHAREDCLIPBOARDMETADATAFMTDATA));
435 if (pMetaDataFmt)
436 {
437 char *pszFmt = NULL;
438 rc = RTStrAAppend(&pszFmt, "VBoxShClURIList");
439 if (RT_SUCCESS(rc))
440 {
441 pMetaDataFmt->uVer = 1;
442 pMetaDataFmt->pvFmt = pszFmt;
443 pMetaDataFmt->cbFmt = (uint32_t)strlen(pszFmt) + 1 /* Include terminating zero */;
444
445 pDataHdr->pvMetaFmt = pMetaDataFmt;
446 pDataHdr->cbMetaFmt = sizeof(SHAREDCLIPBOARDMETADATAFMTDATA) + pMetaDataFmt->cbFmt;
447
448 *ppDataHdr = pDataHdr;
449 }
450 }
451 else
452 rc = VERR_NO_MEMORY;
453
454 if (RT_FAILURE(rc))
455 {
456 RTMemFree(pDataHdr);
457 pDataHdr = NULL;
458 }
459 }
460 else
461 rc = VERR_NO_MEMORY;
462
463 LogFlowFuncLeaveRC(rc);
464 return rc;
465}
466
467/**
468 * Frees a VBOXCLIPBOARDDATAHDR structure.
469 *
470 * @param pDataChunk VBOXCLIPBOARDDATAHDR structure to free.
471 */
472void SharedClipboardURIDataHdrFree(PVBOXCLIPBOARDDATAHDR pDataHdr)
473{
474 if (!pDataHdr)
475 return;
476
477 LogFlowFuncEnter();
478
479 SharedClipboardURIDataHdrDestroy(pDataHdr);
480
481 RTMemFree(pDataHdr);
482 pDataHdr = NULL;
483}
484
485/**
486 * Duplicates (allocates) a VBOXCLIPBOARDDATAHDR structure.
487 *
488 * @returns Duplicated VBOXCLIPBOARDDATAHDR structure on success.
489 * @param pDataHdr VBOXCLIPBOARDDATAHDR to duplicate.
490 */
491PVBOXCLIPBOARDDATAHDR SharedClipboardURIDataHdrDup(PVBOXCLIPBOARDDATAHDR pDataHdr)
492{
493 AssertPtrReturn(pDataHdr, NULL);
494
495 PVBOXCLIPBOARDDATAHDR pDataHdrDup = (PVBOXCLIPBOARDDATAHDR)RTMemAlloc(sizeof(VBOXCLIPBOARDDATAHDR));
496 if (pDataHdrDup)
497 {
498 *pDataHdrDup = *pDataHdr;
499
500 if (pDataHdr->pvMetaFmt)
501 {
502 pDataHdrDup->pvMetaFmt = RTMemDup(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
503 pDataHdrDup->cbMetaFmt = pDataHdr->cbMetaFmt;
504 }
505
506 if (pDataHdr->pvChecksum)
507 {
508 pDataHdrDup->pvChecksum = RTMemDup(pDataHdr->pvChecksum, pDataHdr->cbChecksum);
509 pDataHdrDup->cbChecksum = pDataHdr->cbChecksum;
510 }
511 }
512
513 return pDataHdrDup;
514}
515
516/**
517 * Returns the size (in bytes) of the announced meta data.
518 *
519 * @returns Announced meta data size in bytes.
520 * @param pDataHdr Data header struct to get announced meta data size for.
521 */
522uint32_t SharedClipboardURIDataHdrGetMetaDataSize(PVBOXCLIPBOARDDATAHDR pDataHdr)
523{
524 AssertPtrReturn(pDataHdr, 0);
525
526 return pDataHdr->cbMeta;
527}
528
529/**
530 * Initializes an URI data header struct.
531 *
532 * @returns VBox status code.
533 * @param pDataHdr Data header struct to initialize.
534 */
535int SharedClipboardURIDataHdrInit(PVBOXCLIPBOARDDATAHDR pDataHdr)
536{
537 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
538
539 SharedClipboardURIDataHdrReset(pDataHdr);
540
541 return VINF_SUCCESS;
542}
543
544/**
545 * Destroys an URI data header struct.
546 *
547 * @param pDataHdr Data header struct to destroy.
548 */
549void SharedClipboardURIDataHdrDestroy(PVBOXCLIPBOARDDATAHDR pDataHdr)
550{
551 if (!pDataHdr)
552 return;
553
554 LogFlowFuncEnter();
555
556 if (pDataHdr->pvMetaFmt)
557 {
558 Assert(pDataHdr->cbMetaFmt);
559
560 RTMemFree(pDataHdr->pvMetaFmt);
561 pDataHdr->pvMetaFmt = NULL;
562 pDataHdr->cbMetaFmt = 0;
563 }
564
565 if (pDataHdr->pvChecksum)
566 {
567 Assert(pDataHdr->cbChecksum);
568
569 RTMemFree(pDataHdr->pvChecksum);
570 pDataHdr->pvChecksum = NULL;
571 pDataHdr->cbChecksum = 0;
572 }
573}
574
575/**
576 * Resets a VBOXCLIPBOARDDATAHDR structture.
577 *
578 * @returns VBox status code.
579 * @param pDataHdr VBOXCLIPBOARDDATAHDR structture to reset.
580 */
581void SharedClipboardURIDataHdrReset(PVBOXCLIPBOARDDATAHDR pDataHdr)
582{
583 AssertPtrReturnVoid(pDataHdr);
584
585 LogFlowFuncEnter();
586
587 RT_BZERO(pDataHdr, sizeof(VBOXCLIPBOARDDATAHDR));
588}
589
590/**
591 * Returns whether a given clipboard data header is valid or not.
592 *
593 * @returns \c true if valid, \c false if not.
594 * @param pDataHdr Clipboard data header to validate.
595 */
596bool SharedClipboardURIDataHdrIsValid(PVBOXCLIPBOARDDATAHDR pDataHdr)
597{
598 RT_NOREF(pDataHdr);
599 return true; /** @todo Implement this. */
600}
601
602/**
603 * Creates (allocates) and initializes a VBOXCLIPBOARDDATACHUNK structure.
604 *
605 * @param ppDirData Where to return the created VBOXCLIPBOARDDATACHUNK structure on success.
606 */
607int SharedClipboardURIDataChunkAlloc(PVBOXCLIPBOARDDATACHUNK *ppDataChunk)
608{
609 PVBOXCLIPBOARDDATACHUNK pDataChunk = (PVBOXCLIPBOARDDATACHUNK)RTMemAlloc(sizeof(VBOXCLIPBOARDDATACHUNK));
610 if (!pDataChunk)
611 return VERR_NO_MEMORY;
612
613 int rc = SharedClipboardURIDataChunkInit(pDataChunk);
614 if (RT_SUCCESS(rc))
615 *ppDataChunk = pDataChunk;
616
617 return rc;
618}
619
620/**
621 * Frees a VBOXCLIPBOARDDATACHUNK structure.
622 *
623 * @param pDataChunk VBOXCLIPBOARDDATACHUNK structure to free.
624 */
625void SharedClipboardURIDataChunkFree(PVBOXCLIPBOARDDATACHUNK pDataChunk)
626{
627 if (!pDataChunk)
628 return;
629
630 SharedClipboardURIDataChunkDestroy(pDataChunk);
631 RTMemFree(pDataChunk);
632}
633
634/**
635 * Initializes a VBOXCLIPBOARDDATACHUNK structure.
636 *
637 * @param pDataChunk VBOXCLIPBOARDDATACHUNK structure to initialize.
638 */
639int SharedClipboardURIDataChunkInit(PVBOXCLIPBOARDDATACHUNK pDataChunk)
640{
641 RT_BZERO(pDataChunk, sizeof(VBOXCLIPBOARDDATACHUNK));
642
643 return VINF_SUCCESS;
644}
645
646/**
647 * Initializes a VBOXCLIPBOARDDATACHUNK structure.
648 *
649 * @param pDataChunk VBOXCLIPBOARDDATACHUNK structure to destroy.
650 */
651void SharedClipboardURIDataChunkDestroy(PVBOXCLIPBOARDDATACHUNK pDataChunk)
652{
653 if (pDataChunk->pvData)
654 {
655 RTMemFree(pDataChunk->pvData);
656 pDataChunk->pvData = NULL;
657 pDataChunk->cbData = 0;
658 }
659
660 if (pDataChunk->pvChecksum)
661 {
662 RTMemFree(pDataChunk->pvChecksum);
663 pDataChunk->pvChecksum = NULL;
664 pDataChunk->cbChecksum = 0;
665 }
666}
667
668/**
669 * Returns whether a given clipboard data chunk is valid or not.
670 *
671 * @returns \c true if valid, \c false if not.
672 * @param pDataChunk Clipboard data chunk to validate.
673 */
674bool SharedClipboardURIDataChunkIsValid(PVBOXCLIPBOARDDATACHUNK pDataChunk)
675{
676 RT_NOREF(pDataChunk);
677
678 /** @todo Verify checksum. */
679
680 return true; /** @todo Implement this. */
681}
682
683/**
684 * Creates (allocates) and initializes a VBOXCLIPBOARDDIRDATA structure.
685 *
686 * @param ppDirData Where to return the created VBOXCLIPBOARDDIRDATA structure on success.
687 */
688int SharedClipboardURIDirDataAlloc(PVBOXCLIPBOARDDIRDATA *ppDirData)
689{
690 PVBOXCLIPBOARDDIRDATA pDirData = (PVBOXCLIPBOARDDIRDATA)RTMemAlloc(sizeof(VBOXCLIPBOARDDIRDATA));
691 if (!pDirData)
692 return VERR_NO_MEMORY;
693
694 int rc = SharedClipboardURIDirDataInit(pDirData);
695 if (RT_SUCCESS(rc))
696 *ppDirData = pDirData;
697
698 return rc;
699}
700
701/**
702 * Frees a VBOXCLIPBOARDDIRDATA structure.
703 *
704 * @param pDirData Where to return the created VBOXCLIPBOARDDIRDATA structure on success.
705 */
706void SharedClipboardURIDirDataFree(PVBOXCLIPBOARDDIRDATA pDirData)
707{
708 if (!pDirData)
709 return;
710
711 SharedClipboardURIDirDataDestroy(pDirData);
712 RTMemFree(pDirData);
713}
714
715/**
716 * Initializes a VBOXCLIPBOARDDIRDATA structure.
717 *
718 * @param pDirData VBOXCLIPBOARDDIRDATA structure to initialize.
719 */
720int SharedClipboardURIDirDataInit(PVBOXCLIPBOARDDIRDATA pDirData)
721{
722 RT_BZERO(pDirData, sizeof(VBOXCLIPBOARDDIRDATA));
723
724 return VINF_SUCCESS;
725}
726
727/**
728 * Destroys a VBOXCLIPBOARDDIRDATA structure.
729 *
730 * @param pDirData VBOXCLIPBOARDDIRDATA structure to destroy.
731 */
732void SharedClipboardURIDirDataDestroy(PVBOXCLIPBOARDDIRDATA pDirData)
733{
734 if (!pDirData)
735 return;
736
737 if (pDirData->pszPath)
738 {
739 Assert(pDirData->cbPath);
740 RTStrFree(pDirData->pszPath);
741 pDirData->pszPath = NULL;
742 }
743}
744
745/**
746 * Duplicates (allocates) a VBOXCLIPBOARDDIRDATA structure.
747 *
748 * @returns Duplicated VBOXCLIPBOARDDIRDATA structure on success.
749 * @param pDirData VBOXCLIPBOARDDIRDATA to duplicate.
750 */
751PVBOXCLIPBOARDDIRDATA SharedClipboardURIDirDataDup(PVBOXCLIPBOARDDIRDATA pDirData)
752{
753 AssertPtrReturn(pDirData, NULL);
754
755 PVBOXCLIPBOARDDIRDATA pDirDataDup = (PVBOXCLIPBOARDDIRDATA)RTMemAllocZ(sizeof(VBOXCLIPBOARDDIRDATA));
756 if (pDirDataDup)
757 {
758 *pDirDataDup = *pDirData;
759
760 if (pDirData->pszPath)
761 {
762 pDirDataDup->pszPath = RTStrDup(pDirData->pszPath);
763 if (pDirDataDup->pszPath)
764 pDirDataDup->cbPath = pDirData->cbPath;
765 }
766 }
767
768 return pDirDataDup;
769}
770
771/**
772 * Returns whether given clipboard directory data is valid or not.
773 *
774 * @returns \c true if valid, \c false if not.
775 * @param pDirData Clipboard directory data to validate.
776 */
777bool SharedClipboardURIDirDataIsValid(PVBOXCLIPBOARDDIRDATA pDirData)
778{
779 if ( !pDirData->cbPath
780 || pDirData->cbPath > RTPATH_MAX)
781 return false;
782
783 if (!RTStrIsValidEncoding(pDirData->pszPath))
784 return false;
785
786 return true;
787}
788
789/**
790 * Initializes a VBOXCLIPBOARDFILEHDR structure.
791 *
792 * @param pDirData VBOXCLIPBOARDFILEHDR structure to initialize.
793 */
794int SharedClipboardURIFileHdrInit(PVBOXCLIPBOARDFILEHDR pFileHdr)
795{
796 RT_BZERO(pFileHdr, sizeof(VBOXCLIPBOARDFILEHDR));
797
798 return VINF_SUCCESS;
799}
800
801/**
802 * Destroys a VBOXCLIPBOARDFILEHDR structure.
803 *
804 * @param pFileHdr VBOXCLIPBOARDFILEHDR structure to destroy.
805 */
806void SharedClipboardURIFileHdrDestroy(PVBOXCLIPBOARDFILEHDR pFileHdr)
807{
808 if (!pFileHdr)
809 return;
810
811 if (pFileHdr->pszFilePath)
812 {
813 Assert(pFileHdr->pszFilePath);
814 RTStrFree(pFileHdr->pszFilePath);
815 pFileHdr->pszFilePath = NULL;
816 }
817}
818
819/**
820 * Duplicates (allocates) a VBOXCLIPBOARDFILEHDR structure.
821 *
822 * @returns Duplicated VBOXCLIPBOARDFILEHDR structure on success.
823 * @param pFileHdr VBOXCLIPBOARDFILEHDR to duplicate.
824 */
825PVBOXCLIPBOARDFILEHDR SharedClipboardURIFileHdrDup(PVBOXCLIPBOARDFILEHDR pFileHdr)
826{
827 AssertPtrReturn(pFileHdr, NULL);
828
829 PVBOXCLIPBOARDFILEHDR pFileHdrDup = (PVBOXCLIPBOARDFILEHDR)RTMemAllocZ(sizeof(VBOXCLIPBOARDFILEHDR));
830 if (pFileHdrDup)
831 {
832 *pFileHdrDup = *pFileHdr;
833
834 if (pFileHdr->pszFilePath)
835 {
836 pFileHdrDup->pszFilePath = RTStrDup(pFileHdr->pszFilePath);
837 if (pFileHdrDup->pszFilePath)
838 pFileHdrDup->cbFilePath = pFileHdrDup->cbFilePath;
839 }
840 }
841
842 return pFileHdrDup;
843}
844
845/**
846 * Returns whether a given clipboard file header is valid or not.
847 *
848 * @returns \c true if valid, \c false if not.
849 * @param pFileHdr Clipboard file header to validate.
850 * @param pDataHdr Data header to use for validation.
851 */
852bool SharedClipboardURIFileHdrIsValid(PVBOXCLIPBOARDFILEHDR pFileHdr, PVBOXCLIPBOARDDATAHDR pDataHdr)
853{
854 if ( !pFileHdr->cbFilePath
855 || pFileHdr->cbFilePath > RTPATH_MAX)
856 return false;
857
858 if (!RTStrIsValidEncoding(pFileHdr->pszFilePath))
859 return false;
860
861 if (pFileHdr->cbSize > pDataHdr->cbTotal)
862 return false;
863
864 return true;
865}
866
867/**
868 * Destroys a VBOXCLIPBOARDFILEDATA structure.
869 *
870 * @param pFileData VBOXCLIPBOARDFILEDATA structure to destroy.
871 */
872void SharedClipboardURIFileDataDestroy(PVBOXCLIPBOARDFILEDATA pFileData)
873{
874 if (!pFileData)
875 return;
876
877 if (pFileData->pvData)
878 {
879 Assert(pFileData->cbData);
880 RTMemFree(pFileData->pvData);
881 pFileData->pvData = NULL;
882 }
883}
884
885/**
886 * Duplicates (allocates) a VBOXCLIPBOARDFILEDATA structure.
887 *
888 * @returns Duplicated VBOXCLIPBOARDFILEDATA structure on success.
889 * @param pFileData VBOXCLIPBOARDFILEDATA to duplicate.
890 */
891PVBOXCLIPBOARDFILEDATA SharedClipboardURIFileDataDup(PVBOXCLIPBOARDFILEDATA pFileData)
892{
893 AssertPtrReturn(pFileData, NULL);
894
895 PVBOXCLIPBOARDFILEDATA pFileDataDup = (PVBOXCLIPBOARDFILEDATA)RTMemAllocZ(sizeof(VBOXCLIPBOARDFILEDATA));
896 if (pFileDataDup)
897 {
898 *pFileDataDup = *pFileData;
899
900 if (pFileData->pvData)
901 {
902 pFileDataDup->pvData = RTMemDup(pFileData->pvData, pFileData->cbData);
903 if (pFileDataDup->pvData)
904 pFileDataDup->cbData = pFileDataDup->cbData;
905 }
906
907 if (pFileData->pvChecksum)
908 {
909 pFileDataDup->pvChecksum = RTMemDup(pFileData->pvChecksum, pFileData->cbChecksum);
910 if (pFileDataDup->pvChecksum)
911 pFileDataDup->cbChecksum = pFileData->cbChecksum;
912 }
913 }
914
915 return pFileDataDup;
916}
917
918/**
919 * Returns whether given clipboard file data is valid or not.
920 *
921 * @returns \c true if valid, \c false if not.
922 * @param pFileData Clipboard file data to validate.
923 * @param pDataHdr Data header to use for validation.
924 */
925bool SharedClipboardURIFileDataIsValid(PVBOXCLIPBOARDFILEDATA pFileData, PVBOXCLIPBOARDDATAHDR pDataHdr)
926{
927 RT_NOREF(pFileData, pDataHdr);
928 return true;
929}
930
931/**
932 * Initializes an URI object context.
933 *
934 * @returns VBox status code.
935 * @param pObjCtx URI object context to initialize.
936 */
937int SharedClipboardURIObjCtxInit(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
938{
939 AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER);
940
941 LogFlowFuncEnter();
942
943 pObjCtx->pObj = NULL;
944
945 return VINF_SUCCESS;
946}
947
948/**
949 * Destroys an URI object context.
950 *
951 * @param pObjCtx URI object context to destroy.
952 */
953void SharedClipboardURIObjCtxDestroy(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
954{
955 AssertPtrReturnVoid(pObjCtx);
956
957 LogFlowFuncEnter();
958
959 if (pObjCtx->pObj)
960 {
961 pObjCtx->pObj->Close();
962 /* Note: Do *not* delete pObj here -- the associated URI list will do this. */
963 }
964
965 pObjCtx->pObj = NULL;
966}
967
968/**
969 * Returns the URI object context's URI object.
970 *
971 * @returns Pointer to the URI object context's URI object.
972 * @param pObjCtx URI object context to return the URI object for.
973 */
974SharedClipboardURIObject *SharedClipboardURIObjCtxGetObj(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
975{
976 AssertPtrReturn(pObjCtx, NULL);
977 return pObjCtx->pObj;
978}
979
980/**
981 * Returns if an URI object context is valid or not.
982 *
983 * @returns \c true if valid, \c false if not.
984 * @param pObjCtx URI object context to check.
985 */
986bool SharedClipboardURIObjCtxIsValid(PSHAREDCLIPBOARDCLIENTURIOBJCTX pObjCtx)
987{
988 return ( pObjCtx
989 && pObjCtx->pObj
990 && pObjCtx->pObj->IsComplete() == false
991 && pObjCtx->pObj->IsOpen());
992}
993
994/**
995 * Initializes an URI clipboard transfer struct.
996 *
997 * @returns VBox status code.
998 * @param enmDir Transfer direction.
999 * @param ppTransfer Where to return the created URI transfer struct.
1000 * Must be destroyed by SharedClipboardURITransferDestroy().
1001 */
1002int SharedClipboardURITransferCreate(SHAREDCLIPBOARDURITRANSFERDIR enmDir, PSHAREDCLIPBOARDURITRANSFER *ppTransfer)
1003{
1004 AssertPtrReturn(ppTransfer, VERR_INVALID_POINTER);
1005
1006 LogFlowFuncEnter();
1007
1008 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)RTMemAlloc(sizeof(SHAREDCLIPBOARDURITRANSFER));
1009 if (!pTransfer)
1010 return VERR_NO_MEMORY;
1011
1012 int rc = VINF_SUCCESS;
1013
1014 pTransfer->State.enmDir = enmDir;
1015
1016 pTransfer->State.pHeader = NULL;
1017 pTransfer->State.pMeta = NULL;
1018 pTransfer->pArea = NULL; /* Will be created later if needed. */
1019
1020 pTransfer->Thread.hThread = NIL_RTTHREAD;
1021 pTransfer->Thread.fCancelled = false;
1022 pTransfer->Thread.fStarted = false;
1023
1024 pTransfer->pvUser = NULL;
1025 pTransfer->cbUser = 0;
1026
1027 pTransfer->pURIList = new SharedClipboardURIList();
1028 if (!pTransfer->pURIList)
1029 {
1030 RTMemFree(pTransfer);
1031 return VERR_NO_MEMORY;
1032 }
1033
1034 rc = SharedClipboardURIObjCtxInit(&pTransfer->ObjCtx);
1035 if (RT_SUCCESS(rc))
1036 {
1037 *ppTransfer = pTransfer;
1038 }
1039
1040 LogFlowFuncLeaveRC(rc);
1041 return rc;
1042}
1043
1044/**
1045 * Destroys an URI clipboard transfer context struct.
1046 *
1047 * @returns VBox status code.
1048 * @param pURI URI clipboard transfer to destroy.
1049 */
1050int SharedClipboardURITransferDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1051{
1052 if (!pTransfer)
1053 return VINF_SUCCESS;
1054
1055 LogFlowFuncEnter();
1056
1057 int rc = sharedClipboardURITransferThreadDestroy(pTransfer, 30 * 1000 /* Timeout in ms */);
1058 if (RT_FAILURE(rc))
1059 return rc;
1060
1061 SharedClipboardURIDataHdrDestroy(pTransfer->State.pHeader);
1062 SharedClipboardMetaDataDestroy(pTransfer->State.pMeta);
1063
1064 if (pTransfer->pURIList)
1065 {
1066 delete pTransfer->pURIList;
1067 pTransfer->pURIList = NULL;
1068 }
1069
1070 if (pTransfer->pProvider)
1071 {
1072 delete pTransfer->pProvider;
1073 pTransfer->pProvider = NULL;
1074 }
1075
1076 SharedClipboardURIObjCtxDestroy(&pTransfer->ObjCtx);
1077
1078 RTMemFree(pTransfer);
1079 pTransfer = NULL;
1080
1081 LogFlowFuncLeave();
1082
1083 return VINF_SUCCESS;
1084}
1085
1086/**
1087 * Prepares everything needed for a read / write transfer to begin.
1088 *
1089 * @returns VBox status code.
1090 * @param pTransfer URI clipboard transfer to prepare.
1091 */
1092int SharedClipboardURITransferPrepare(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1093{
1094 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1095
1096 LogFlowFuncEnter();
1097
1098 AssertPtrReturn(pTransfer->State.pMeta, VERR_WRONG_ORDER);
1099 AssertPtrReturn(pTransfer->pURIList, VERR_WRONG_ORDER);
1100
1101 PSHAREDCLIPBOARDMETADATA pMeta = pTransfer->State.pMeta;
1102 AssertPtrReturn(pMeta, VERR_WRONG_ORDER);
1103
1104 int rc;
1105
1106 LogFlowFunc(("enmDir=%RU32\n", pTransfer->State.enmDir));
1107
1108 if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_READ)
1109 {
1110 rc = pTransfer->pURIList->SetFromURIData(SharedClipboardMetaDataRaw(pMeta),
1111 SharedClipboardMetaDataGetUsed(pMeta),
1112 SHAREDCLIPBOARDURILIST_FLAGS_NONE);
1113 /** @todo Verify pvMetaFmt. */
1114
1115 sharedClipboardURITransferMetaDataDestroyInternal(pTransfer);
1116 }
1117 else if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_WRITE)
1118 {
1119 rc = pTransfer->pURIList->AppendURIPathsFromList((char *)SharedClipboardMetaDataRaw(pMeta),
1120 SharedClipboardMetaDataGetUsed(pMeta),
1121 SHAREDCLIPBOARDURILIST_FLAGS_KEEP_OPEN);
1122 if (RT_SUCCESS(rc))
1123 {
1124 PVBOXCLIPBOARDDATAHDR pHeader;
1125 rc = SharedClipboardURIDataHdrAlloc(&pHeader);
1126 if (RT_SUCCESS(rc))
1127 {
1128 /* The total size also contains the size of the meta data. */
1129 uint64_t cbTotal = pMeta->cbUsed;
1130 cbTotal += pTransfer->pURIList->GetTotalBytes();
1131
1132 pHeader->cbTotal = cbTotal;
1133 pHeader->cbMeta = (uint32_t)SharedClipboardMetaDataGetUsed(pMeta);
1134 pHeader->cObjects = pTransfer->pURIList->GetTotalCount();
1135
1136 SharedClipboardURIDataHdrDestroy(pTransfer->State.pHeader);
1137
1138 if (RT_SUCCESS(rc))
1139 {
1140 LogFlowFunc(("Writing cbTotal=%RU64, cbMeta=%RU32, cObj=%RU64\n",
1141 pHeader->cbTotal, pHeader->cbMeta, pHeader->cObjects));
1142
1143 pTransfer->State.pHeader = pHeader;
1144 }
1145 else
1146 SharedClipboardURIDataHdrFree(pHeader);
1147 }
1148 }
1149 }
1150 else
1151 {
1152 rc = VERR_NOT_IMPLEMENTED;
1153 AssertFailed();
1154 }
1155
1156 if (RT_SUCCESS(rc))
1157 {
1158 /** @todo Add checksum support. */
1159 }
1160
1161 LogFlowFuncLeaveRC(rc);
1162 return rc;
1163}
1164
1165/**
1166 * Creates an URI provider for a given transfer.
1167 *
1168 * @returns VBox status code.
1169 * @param pTransfer Transfer to create URI provider for.
1170 * @param pProviderCtx Provider creation context to use for provider creation.
1171 */
1172int SharedClipboardURITransferProviderCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer,
1173 PSHAREDCLIPBOARDPROVIDERCREATIONCTX pProviderCtx)
1174{
1175 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1176 AssertPtrReturn(pProviderCtx, VERR_INVALID_POINTER);
1177
1178 LogFlowFuncEnter();
1179
1180 int rc;
1181
1182 pTransfer->pProvider = SharedClipboardProvider::Create(pProviderCtx);
1183 if (pTransfer->pProvider)
1184 {
1185 rc = VINF_SUCCESS;
1186 }
1187 else
1188 rc = VERR_NO_MEMORY;
1189
1190 LogFlowFuncLeaveRC(rc);
1191 return rc;
1192}
1193
1194/**
1195 * Resets an clipboard URI transfer.
1196 *
1197 * @param pTransfer URI clipboard transfer to reset.
1198 */
1199void SharedClipboardURITransferReset(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1200{
1201 AssertPtrReturnVoid(pTransfer);
1202
1203 LogFlowFuncEnter();
1204
1205 /** @todo Anything else to do here? */
1206
1207 if (pTransfer->pProvider)
1208 pTransfer->pProvider->Reset();
1209
1210 if (pTransfer->pURIList)
1211 pTransfer->pURIList->Clear();
1212
1213 SharedClipboardURIObjCtxDestroy(&pTransfer->ObjCtx);
1214}
1215
1216/**
1217 * Returns the clipboard area for a clipboard URI transfer.
1218 *
1219 * @returns Current clipboard area, or NULL if none.
1220 * @param pTransfer URI clipboard transfer to return clipboard area for.
1221 */
1222SharedClipboardArea *SharedClipboardURITransferGetArea(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1223{
1224 AssertPtrReturn(pTransfer, NULL);
1225
1226 return pTransfer->pArea;
1227}
1228
1229/**
1230 * Returns the current object context of a clipboard URI transfer.
1231 *
1232 * @returns Current object context, or NULL if none.
1233 * @param pTransfer URI clipboard transfer to return object context for.
1234 */
1235PSHAREDCLIPBOARDCLIENTURIOBJCTX SharedClipboardURITransferGetCurrentObjCtx(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1236{
1237 /* At the moment we only have one object context per transfer at a time. */
1238 return &pTransfer->ObjCtx;
1239}
1240
1241/**
1242 * Returns the current URI object for a clipboard URI transfer.
1243 *
1244 * @returns Current URI object, or NULL if none.
1245 * @param pTransfer URI clipboard transfer to return current URI object for.
1246 */
1247const SharedClipboardURIObject *SharedClipboardURITransferGetCurrentObject(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1248{
1249 AssertPtrReturn(pTransfer, NULL);
1250
1251 if (pTransfer->pURIList)
1252 return pTransfer->pURIList->First();
1253
1254 return NULL;
1255}
1256
1257/**
1258 * Returns the provider for a clipboard URI transfer.
1259 *
1260 * @returns Current provider, or NULL if none.
1261 * @param pTransfer URI clipboard transfer to return provider for.
1262 */
1263SharedClipboardProvider *SharedClipboardURITransferGetProvider(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1264{
1265 AssertPtrReturn(pTransfer, NULL);
1266
1267 return pTransfer->pProvider;
1268}
1269
1270/**
1271 * Returns the URI list for a clipboard URI transfer.
1272 *
1273 * @returns Pointer to URI list.
1274 * @param pTransfer URI clipboard transfer to return URI list for.
1275 */
1276SharedClipboardURIList *SharedClipboardURITransferGetList(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1277{
1278 AssertPtrReturn(pTransfer, NULL);
1279
1280 return pTransfer->pURIList;
1281}
1282
1283/**
1284 * Returns the current URI object for a clipboard URI transfer.
1285 *
1286 * @returns Pointer to URI object.
1287 * @param pTransfer URI clipboard transfer to return URI object for.
1288 */
1289SharedClipboardURIObject *SharedClipboardURITransferGetObject(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint64_t uIdx)
1290{
1291 AssertPtrReturn(pTransfer, NULL);
1292
1293 if (!pTransfer->pURIList)
1294 return NULL;
1295
1296 return pTransfer->pURIList->At(uIdx);
1297}
1298
1299/**
1300 * Runs (starts) an URI transfer, either in synchronous or asynchronous (threaded) mode.
1301 *
1302 * @returns VBox status code.
1303 * @param pTransfer URI clipboard transfer to run.
1304 * @param fAsync Whether to run the transfer synchronously or asynchronously.
1305 */
1306int SharedClipboardURITransferRun(PSHAREDCLIPBOARDURITRANSFER pTransfer, bool fAsync)
1307{
1308 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1309
1310 int rc;
1311
1312 LogFlowFunc(("fAsync=%RTbool\n", fAsync));
1313
1314 if (fAsync)
1315 {
1316 rc = sharedClipboardURITransferThreadCreate(pTransfer);
1317 }
1318 else
1319 {
1320 if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_READ)
1321 rc = SharedClipboardURITransferRead(pTransfer);
1322 else if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_WRITE)
1323 rc = SharedClipboardURITransferWrite(pTransfer);
1324 else
1325 rc = VERR_NOT_IMPLEMENTED;
1326 }
1327
1328 LogFlowFuncLeaveRC(rc);
1329 return rc;
1330}
1331
1332/**
1333 * Sets or unsets the callback table to be used for a clipboard URI transfer.
1334 *
1335 * @returns VBox status code.
1336 * @param pTransfer URI clipboard transfer to set callbacks for.
1337 * @param pCallbacks Pointer to callback table to set. Specify NULL to unset existing callbacks.
1338 */
1339void SharedClipboardURITransferSetCallbacks(PSHAREDCLIPBOARDURITRANSFER pTransfer, PSHAREDCLIPBOARDURITRANSFERCALLBACKS pCallbacks)
1340{
1341 AssertPtrReturnVoid(pTransfer);
1342 /* pCallbacks might be NULL to unset callbacks. */
1343
1344 LogFlowFunc(("pCallbacks=%p\n", pCallbacks));
1345
1346 if (pCallbacks)
1347 {
1348 pTransfer->Callbacks = *pCallbacks;
1349 }
1350 else
1351 RT_ZERO(pTransfer->Callbacks);
1352}
1353
1354/**
1355 * Creates a thread for a clipboard URI transfer.
1356 *
1357 * @returns VBox status code.
1358 * @param pTransfer URI clipboard transfer to create thread for.
1359 */
1360static int sharedClipboardURITransferThreadCreate(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1361{
1362 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1363
1364 PFNRTTHREAD pfnRTThread = NULL;
1365
1366 if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_READ)
1367 pfnRTThread = sharedClipboardURITransferReadThread;
1368 else if (pTransfer->State.enmDir == SHAREDCLIPBOARDURITRANSFERDIR_WRITE)
1369 pfnRTThread = sharedClipboardURITransferWriteThread;
1370
1371 AssertPtrReturn(pfnRTThread, VERR_NOT_SUPPORTED);
1372
1373 /* Spawn a worker thread, so that we don't block the window thread for too long. */
1374 int rc = RTThreadCreate(&pTransfer->Thread.hThread, pfnRTThread,
1375 pTransfer /* pvUser */, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
1376 "shclp");
1377 if (RT_SUCCESS(rc))
1378 {
1379 int rc2 = RTThreadUserWait(pTransfer->Thread.hThread, 30 * 1000 /* Timeout in ms */);
1380 AssertRC(rc2);
1381
1382 if (!pTransfer->Thread.fStarted) /* Did the thread fail to start? */
1383 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
1384 }
1385
1386 LogFlowFuncLeaveRC(rc);
1387 return rc;
1388}
1389
1390/**
1391 * Destroys a thread of a clipboard URI transfer.
1392 *
1393 * @returns VBox status code.
1394 * @param pTransfer URI clipboard transfer to destroy thread for.
1395 * @param uTimeoutMs Timeout (in ms) to wait for thread creation.
1396 */
1397static int sharedClipboardURITransferThreadDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer, RTMSINTERVAL uTimeoutMs)
1398{
1399 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1400
1401 if (pTransfer->Thread.hThread == NIL_RTTHREAD)
1402 return VINF_SUCCESS;
1403
1404 int rcThread = VERR_WRONG_ORDER;
1405 int rc = RTThreadWait(pTransfer->Thread.hThread, uTimeoutMs, &rcThread);
1406
1407 LogFlowFunc(("Waiting for thread resulted in %Rrc (thread exited with %Rrc)\n", rc, rcThread));
1408
1409 return rc;
1410}
1411
1412/**
1413 * Reads all URI objects using the connected provider.
1414 *
1415 * @returns VBox status code.
1416 * @param pTransfer Transfer to read objects for.
1417 */
1418int SharedClipboardURITransferRead(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1419{
1420 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1421
1422 LogFlowFuncEnter();
1423
1424 int rc = SharedClipboardURITransferMetaDataRead(pTransfer, NULL /* pcbRead */);
1425 if (RT_SUCCESS(rc))
1426 {
1427 rc = SharedClipboardURITransferReadObjects(pTransfer);
1428 if (RT_SUCCESS(rc))
1429 {
1430 if (pTransfer->Callbacks.pfnTransferComplete)
1431 {
1432 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1433 pTransfer->Callbacks.pfnTransferComplete(&callbackData, rc);
1434 }
1435 }
1436 }
1437
1438 if (RT_FAILURE(rc))
1439 {
1440 if (pTransfer->Callbacks.pfnTransferError)
1441 {
1442 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1443 pTransfer->Callbacks.pfnTransferError(&callbackData, rc);
1444 }
1445 }
1446
1447 LogFlowFuncLeaveRC(rc);
1448 return rc;
1449}
1450
1451/**
1452 * Reads all URI objects using the connected provider.
1453 *
1454 * @returns VBox status code.
1455 * @param pTransfer Transfer to read objects for.
1456 */
1457int SharedClipboardURITransferReadObjects(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1458{
1459 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1460
1461 LogFlowFuncEnter();
1462
1463 int rc = VERR_NOT_IMPLEMENTED;
1464
1465 LogFlowFuncLeaveRC(rc);
1466 return rc;
1467}
1468
1469/**
1470 * Thread for transferring (reading) URI objects from source to the target.
1471 * For target to source transfers we utilize our own IDataObject / IStream implementations.
1472 *
1473 * @returns VBox status code.
1474 * @param hThread Thread handle.
1475 * @param pvUser User arguments; is PSHAREDCLIPBOARDURITRANSFER.
1476 */
1477static int sharedClipboardURITransferReadThread(RTTHREAD hThread, void *pvUser)
1478{
1479 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1480
1481 LogFlowFuncEnter();
1482
1483 /* At the moment we only support one transfer at a time. */
1484 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)pvUser;
1485 AssertPtr(pTransfer->pProvider);
1486
1487 int rc = VINF_SUCCESS;
1488
1489 if (RT_SUCCESS(rc))
1490 pTransfer->Thread.fStarted = true;
1491
1492 int rc2 = RTThreadUserSignal(hThread);
1493 const bool fSignalled = RT_SUCCESS(rc2);
1494
1495 if (RT_SUCCESS(rc))
1496 rc = SharedClipboardURITransferRead(pTransfer);
1497
1498 if (!fSignalled)
1499 {
1500 rc2 = RTThreadUserSignal(hThread);
1501 AssertRC(rc2);
1502 }
1503
1504 LogFlowFuncLeaveRC(rc);
1505 return rc;
1506}
1507
1508/**
1509 * Creates the internal meta data buffer of an URI clipboard transfer.
1510 *
1511 * @returns VBox status code.
1512 * @param pTransfer URI clipboard transfer to create internal meta data for.
1513 * @param cbSize Size (in bytes) of meta data buffer to create. An existing meta data buffer
1514 * will be resized accordingly.
1515 */
1516static int sharedClipboardURITransferMetaDataCreateInternal(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint32_t cbSize)
1517{
1518 int rc;
1519
1520 LogFlowFuncEnter();
1521
1522 if (pTransfer->State.pMeta == NULL)
1523 {
1524 pTransfer->State.pMeta = (PSHAREDCLIPBOARDMETADATA)RTMemAlloc(sizeof(SHAREDCLIPBOARDMETADATA));
1525 if (pTransfer->State.pMeta)
1526 {
1527 /** @todo Make meta data format handling more flexible. */
1528 rc = SharedClipboardMetaDataInit(pTransfer->State.pMeta, SHAREDCLIPBOARDMETADATAFMT_URI_LIST);
1529 }
1530 else
1531 rc = VERR_NO_MEMORY;
1532 }
1533 else
1534 rc = SharedClipboardMetaDataResize(pTransfer->State.pMeta, cbSize);
1535
1536 LogFlowFuncLeaveRC(rc);
1537 return rc;
1538}
1539
1540/**
1541 * Destroys a clipboard URI transfer's internal meta data.
1542 *
1543 * @param pTransfer URI clipboard transfer to destroy internal meta data of.
1544 */
1545static void sharedClipboardURITransferMetaDataDestroyInternal(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1546{
1547 if (!pTransfer->State.pMeta)
1548 return;
1549
1550 LogFlowFuncEnter();
1551
1552 /* We're done processing the meta data, so just destroy it. */
1553 SharedClipboardMetaDataDestroy(pTransfer->State.pMeta);
1554
1555 RTMemFree(pTransfer->State.pMeta);
1556 pTransfer->State.pMeta = NULL;
1557}
1558
1559/**
1560 * Adds meta data for a clipboard URI transfer, internal version.
1561 *
1562 * @returns VBox status code.
1563 * @param pTransfer URI clipboard transfer to set meta data for.
1564 * @param pvMeta Pointer to meta data buffer.
1565 * @param cbMeta Size (in bytes) of meta data buffer.
1566 */
1567static int sharedClipboardURITransferMetaDataAddInternal(PSHAREDCLIPBOARDURITRANSFER pTransfer,
1568 const void *pvMeta, uint32_t cbMeta)
1569{
1570 LogFlowFunc(("pvMeta=%p, cbMeta=%RU32\n", pvMeta, cbMeta));
1571
1572 int rc = SharedClipboardMetaDataAdd(pTransfer->State.pMeta, pvMeta, cbMeta);
1573
1574 LogFlowFuncLeaveRC(rc);
1575 return rc;
1576}
1577
1578/**
1579 * Adds meta data for a clipboard URI transfer.
1580 *
1581 * @returns VBox status code.
1582 * @param pTransfer URI clipboard transfer to set meta data for.
1583 * @param pvMeta Pointer to meta data buffer.
1584 * @param cbMeta Size (in bytes) of meta data buffer.
1585 */
1586int SharedClipboardURITransferMetaDataAdd(PSHAREDCLIPBOARDURITRANSFER pTransfer, const void *pvMeta, uint32_t cbMeta)
1587{
1588 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1589
1590 LogFlowFuncEnter();
1591
1592 int rc = sharedClipboardURITransferMetaDataCreateInternal(pTransfer, cbMeta);
1593 if (RT_SUCCESS(rc))
1594 rc = sharedClipboardURITransferMetaDataAddInternal(pTransfer, pvMeta, cbMeta);
1595
1596 LogFlowFuncLeaveRC(rc);
1597 return rc;
1598}
1599
1600/**
1601 * Returns whether the meta data is in a complete state (e.g. completetely read / written) or not.
1602 *
1603 * @returns \c true if meta data is complete, \c false if not.
1604 * @param pTransfer URI clipboard transfer to get completion status of meta data for.
1605 */
1606bool SharedClipboardURITransferMetaDataIsComplete(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1607{
1608 AssertPtrReturn(pTransfer->State.pHeader, false);
1609 AssertPtrReturn(pTransfer->State.pMeta, false);
1610
1611 return SharedClipboardMetaDataGetUsed(pTransfer->State.pMeta) == pTransfer->State.pHeader->cbMeta;
1612}
1613
1614/**
1615 * Reads meta for a clipboard URI transfer.
1616 *
1617 * @returns VBox status code.
1618 * @param pTransfer URI clipboard transfer to read meta data for.
1619 * @param pcbRead How much meta data (in bytes) was read on success.
1620 */
1621int SharedClipboardURITransferMetaDataRead(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint32_t *pcbRead)
1622{
1623 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1624
1625 LogFlowFuncEnter();
1626
1627 /* Destroy any former meta data. */
1628 SharedClipboardMetaDataDestroy(pTransfer->State.pMeta);
1629
1630 uint32_t cbReadTotal = 0;
1631
1632 int rc = pTransfer->pProvider->ReadDataHdr(&pTransfer->State.pHeader);
1633 if (RT_SUCCESS(rc))
1634 {
1635 uint32_t cbMeta = _4K; /** @todo Improve. */
1636 void *pvMeta = RTMemAlloc(cbMeta);
1637
1638 if (pvMeta)
1639 {
1640 uint32_t cbMetaToRead = pTransfer->State.pHeader->cbMeta;
1641 while (cbMetaToRead)
1642 {
1643 uint32_t cbMetaRead;
1644 rc = pTransfer->pProvider->ReadDataChunk(pTransfer->State.pHeader, pvMeta, cbMeta, 0 /* fFlags */, &cbMetaRead);
1645 if (RT_SUCCESS(rc))
1646 rc = sharedClipboardURITransferMetaDataAddInternal(pTransfer, pvMeta, cbMeta);
1647
1648 if (RT_FAILURE(rc))
1649 break;
1650
1651 Assert(cbMetaToRead >= cbMetaRead);
1652 cbMetaToRead -= cbMetaRead;
1653
1654 cbReadTotal += cbReadTotal;
1655 }
1656
1657 RTMemFree(pvMeta);
1658
1659 if (RT_SUCCESS(rc))
1660 {
1661 if (pcbRead)
1662 *pcbRead = cbReadTotal;
1663 }
1664 }
1665 else
1666 rc = VERR_NO_MEMORY;
1667 }
1668
1669 LogFlowFuncLeaveRC(rc);
1670 return rc;
1671}
1672
1673/**
1674 * Writes the actual meta data.
1675 *
1676 * @returns IPRT status code.
1677 * @param pTransfer Transfer to write meta data for.
1678 * @param pcbWritten How much bytes were written on success. Optional.
1679 */
1680int SharedClipboardURITransferMetaDataWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer, uint32_t *pcbWritten)
1681{
1682 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1683
1684 AssertPtr(pTransfer->pProvider);
1685
1686 LogFlowFuncEnter();
1687
1688 AssertPtrReturn(pTransfer->State.pHeader, VERR_WRONG_ORDER);
1689 AssertPtrReturn(pTransfer->State.pMeta, VERR_WRONG_ORDER);
1690
1691 uint32_t cbWrittenTotal = 0;
1692
1693 int rc = pTransfer->pProvider->WriteDataHdr(pTransfer->State.pHeader);
1694 if (RT_SUCCESS(rc))
1695 {
1696 /* Sanity. */
1697 Assert(pTransfer->State.pHeader->cbMeta == pTransfer->State.pMeta->cbUsed);
1698
1699 uint32_t cbMetaToWrite = pTransfer->State.pHeader->cbMeta;
1700 while (cbMetaToWrite)
1701 {
1702 uint32_t cbMetaWritten;
1703 rc = pTransfer->pProvider->WriteDataChunk(pTransfer->State.pHeader, (uint8_t *)pTransfer->State.pMeta->pvMeta + cbWrittenTotal,
1704 cbMetaToWrite, 0 /* fFlags */, &cbMetaWritten);
1705 if (RT_FAILURE(rc))
1706 break;
1707
1708 Assert(cbMetaToWrite >= cbMetaWritten);
1709 cbMetaToWrite -= cbMetaWritten;
1710
1711 cbWrittenTotal += cbMetaWritten;
1712 Assert(cbWrittenTotal <= pTransfer->State.pHeader->cbMeta);
1713 }
1714
1715 if (RT_SUCCESS(rc))
1716 {
1717 if (pcbWritten)
1718 *pcbWritten = cbWrittenTotal;
1719 }
1720 }
1721
1722 LogFlowFuncLeaveRC(rc);
1723 return rc;
1724}
1725
1726/**
1727 * Writes all URI objects using the connected provider.
1728 *
1729 * @returns VBox status code.
1730 * @param pTransfer Transfer to write objects for.
1731 */
1732int SharedClipboardURITransferWriteObjects(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1733{
1734 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1735
1736 LogFlowFuncEnter();
1737
1738 int rc = VINF_SUCCESS;
1739
1740 AssertPtrReturn(pTransfer->pURIList, VERR_WRONG_ORDER);
1741 AssertPtrReturn(pTransfer->pProvider, VERR_WRONG_ORDER);
1742
1743 while (!pTransfer->pURIList->IsEmpty())
1744 {
1745 SharedClipboardURIObject *pObj = pTransfer->pURIList->First();
1746 AssertPtrBreakStmt(pObj, rc = VERR_INVALID_POINTER);
1747
1748 switch (pObj->GetType())
1749 {
1750 case SharedClipboardURIObject::Type_Directory:
1751 {
1752 RTCString strPath = pObj->GetDestPathAbs();
1753 LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n",
1754 strPath.c_str(), strPath.length(), pObj->GetMode()));
1755
1756 VBOXCLIPBOARDDIRDATA dirData;
1757 SharedClipboardURIDirDataInit(&dirData);
1758
1759 dirData.pszPath = RTStrDup(strPath.c_str());
1760 dirData.cbPath = (uint32_t)strlen(dirData.pszPath) + 1 /* Include termination */;
1761
1762 rc = pTransfer->pProvider->WriteDirectory(&dirData);
1763
1764 SharedClipboardURIDirDataDestroy(&dirData);
1765 break;
1766 }
1767
1768 case SharedClipboardURIObject::Type_File:
1769 {
1770 AssertBreakStmt(pObj->IsOpen(), rc = VERR_INVALID_STATE);
1771
1772 RTCString strPath = pObj->GetDestPathAbs();
1773
1774 LogFlowFunc(("strFile=%s (%zu), cbSize=%RU64, fMode=0x%x\n", strPath.c_str(), strPath.length(),
1775 pObj->GetSize(), pObj->GetMode()));
1776
1777 VBOXCLIPBOARDFILEHDR fileHdr;
1778 SharedClipboardURIFileHdrInit(&fileHdr);
1779
1780 fileHdr.pszFilePath = RTStrDup(strPath.c_str());
1781 fileHdr.cbFilePath = (uint32_t)strlen(fileHdr.pszFilePath) + 1 /* Include termination */;
1782 fileHdr.cbSize = pObj->GetSize();
1783 fileHdr.fFlags = 0;
1784 fileHdr.fMode = pObj->GetMode();
1785
1786 rc = pTransfer->pProvider->WriteFileHdr(&fileHdr);
1787 SharedClipboardURIFileHdrDestroy(&fileHdr);
1788
1789 if (RT_FAILURE(rc))
1790 break;
1791
1792 uint32_t cbData = _64K; /** @todo Improve. */
1793 void *pvData = RTMemAlloc(cbData);
1794
1795 AssertPtrBreakStmt(pvData, rc = VERR_NO_MEMORY);
1796
1797 while (!pObj->IsComplete())
1798 {
1799 uint32_t cbRead;
1800 rc = pObj->Read(pvData, cbData, &cbRead);
1801 if (RT_SUCCESS(rc))
1802 {
1803 rc = pTransfer->pProvider->WriteFileData(pvData, cbRead);
1804 }
1805
1806 if (RT_FAILURE(rc))
1807 break;
1808 }
1809
1810 RTMemFree(pvData);
1811 pvData = NULL;
1812 break;
1813 }
1814
1815 default:
1816 AssertFailed();
1817 break;
1818 }
1819
1820 if (RT_FAILURE(rc))
1821 break;
1822
1823 /* Only remove current object on success. */
1824 pTransfer->pURIList->RemoveFirst();
1825 }
1826
1827 LogFlowFuncLeaveRC(rc);
1828 return rc;
1829}
1830
1831/**
1832 * Thread for transferring (writing) URI objects from source to the target.
1833 * For target to source transfers we utilize our own IDataObject / IStream implementations.
1834 *
1835 * @returns VBox status code.
1836 * @param hThread Thread handle.
1837 * @param pvUser User arguments; is PSHAREDCLIPBOARDURITRANSFER.
1838 */
1839static int sharedClipboardURITransferWriteThread(RTTHREAD hThread, void *pvUser)
1840{
1841 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1842
1843 LogFlowFuncEnter();
1844
1845 /* At the moment we only support one transfer at a time. */
1846 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)pvUser;
1847 AssertPtr(pTransfer->pProvider);
1848
1849 int rc = VINF_SUCCESS;
1850
1851 if (RT_SUCCESS(rc))
1852 pTransfer->Thread.fStarted = true;
1853
1854 int rc2 = RTThreadUserSignal(hThread);
1855 const bool fSignalled = RT_SUCCESS(rc2);
1856
1857 if (RT_SUCCESS(rc))
1858 rc = SharedClipboardURITransferWrite(pTransfer);
1859
1860 if (!fSignalled)
1861 {
1862 rc2 = RTThreadUserSignal(hThread);
1863 AssertRC(rc2);
1864 }
1865
1866 LogFlowFuncLeaveRC(rc);
1867 return rc;
1868}
1869
1870/**
1871 * Main function to write a clipboard URI transfer.
1872 *
1873 * @returns VBox status code.
1874 * @param pURI URI clipboard context to write.
1875 */
1876int SharedClipboardURITransferWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer)
1877{
1878 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1879
1880 LogFlowFuncEnter();
1881
1882 int rc = SharedClipboardURITransferMetaDataWrite(pTransfer, NULL /* pcbWritten */);
1883 if (RT_SUCCESS(rc))
1884 {
1885 rc = SharedClipboardURITransferWriteObjects(pTransfer);
1886 if (RT_SUCCESS(rc))
1887 {
1888 if (pTransfer->Callbacks.pfnTransferComplete)
1889 {
1890 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1891 pTransfer->Callbacks.pfnTransferComplete(&callbackData, rc);
1892 }
1893 }
1894 }
1895
1896 if (RT_FAILURE(rc))
1897 {
1898 if (pTransfer->Callbacks.pfnTransferError)
1899 {
1900 SHAREDCLIPBOARDURITRANSFERCALLBACKDATA callbackData = { pTransfer, pTransfer->Callbacks.pvUser };
1901 pTransfer->Callbacks.pfnTransferError(&callbackData, rc);
1902 }
1903 }
1904
1905 LogFlowFuncLeaveRC(rc);
1906 return rc;
1907}
1908
1909/**
1910 * Initializes a clipboard URI transfer.
1911 *
1912 * @returns VBox status code.
1913 * @param pURI URI clipboard context to initialize.
1914 */
1915int SharedClipboardURICtxInit(PSHAREDCLIPBOARDURICTX pURI)
1916{
1917 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
1918
1919 LogFlowFuncEnter();
1920
1921 int rc = RTCritSectInit(&pURI->CritSect);
1922 if (RT_SUCCESS(rc))
1923 {
1924 RTListInit(&pURI->List);
1925
1926 pURI->cTransfers = 0;
1927 pURI->cMaxTransfers = 1; /* For now we only support one transfer per client at a time. */
1928
1929#ifdef DEBUG_andy
1930 pURI->cMaxTransfers = UINT32_MAX;
1931#endif
1932
1933 SharedClipboardURICtxReset(pURI);
1934 }
1935
1936 return VINF_SUCCESS;
1937}
1938
1939/**
1940 * Destroys an URI clipboard information context struct.
1941 *
1942 * @param pURI URI clipboard context to destroy.
1943 */
1944void SharedClipboardURICtxDestroy(PSHAREDCLIPBOARDURICTX pURI)
1945{
1946 AssertPtrReturnVoid(pURI);
1947
1948 RTCritSectDelete(&pURI->CritSect);
1949
1950 PSHAREDCLIPBOARDURITRANSFER pTransfer, pTransferNext;
1951 RTListForEachSafe(&pURI->List, pTransfer, pTransferNext, SHAREDCLIPBOARDURITRANSFER, Node)
1952 {
1953 SharedClipboardURITransferDestroy(pTransfer);
1954 RTListNodeRemove(&pTransfer->Node);
1955 }
1956
1957 LogFlowFuncEnter();
1958}
1959
1960/**
1961 * Resets an clipboard URI transfer.
1962 *
1963 * @param pURI URI clipboard context to reset.
1964 */
1965void SharedClipboardURICtxReset(PSHAREDCLIPBOARDURICTX pURI)
1966{
1967 AssertPtrReturnVoid(pURI);
1968
1969 LogFlowFuncEnter();
1970
1971 PSHAREDCLIPBOARDURITRANSFER pTransfer;
1972 RTListForEach(&pURI->List, pTransfer, SHAREDCLIPBOARDURITRANSFER, Node)
1973 SharedClipboardURITransferReset(pTransfer);
1974}
1975
1976/**
1977 * Adds a new URI transfer to an clipboard URI transfer.
1978 *
1979 * @returns VBox status code.
1980 * @param pURI URI clipboard context to add transfer to.
1981 * @param pTransfer Pointer to URI clipboard transfer to add.
1982 */
1983int SharedClipboardURICtxTransferAdd(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
1984{
1985 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
1986 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
1987
1988 LogFlowFuncEnter();
1989
1990 if (pURI->cTransfers == pURI->cMaxTransfers)
1991 return VERR_SHCLPB_MAX_TRANSFERS_REACHED;
1992
1993 RTListAppend(&pURI->List, &pTransfer->Node);
1994 pURI->cTransfers++;
1995
1996 return VINF_SUCCESS;
1997}
1998
1999/**
2000 * Removes an URI transfer from a clipboard URI transfer.
2001 *
2002 * @returns VBox status code.
2003 * @param pURI URI clipboard context to remove transfer from.
2004 * @param pTransfer Pointer to URI clipboard transfer to remove.
2005 */
2006int SharedClipboardURICtxTransferRemove(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
2007{
2008 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
2009 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2010
2011 LogFlowFuncEnter();
2012
2013 /* Sanity. */
2014 AssertReturn(pURI->cTransfers, VERR_WRONG_ORDER);
2015
2016 int rc = SharedClipboardURITransferDestroy(pTransfer);
2017 if (RT_SUCCESS(rc))
2018 {
2019
2020 RTListNodeRemove(&pTransfer->Node);
2021 Assert(pURI->cTransfers);
2022 pURI->cTransfers--;
2023 }
2024
2025 LogFlowFuncLeaveRC(rc);
2026 return rc;
2027}
2028
2029/**
2030 * Returns a specific URI transfer, internal version.
2031 *
2032 * @returns URI transfer, or NULL if not found.
2033 * @param pURI URI clipboard context to return transfer for.
2034 * @param uIdx Index of the transfer to return.
2035 */
2036static PSHAREDCLIPBOARDURITRANSFER sharedClipboardURICtxGetTransferInternal(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
2037{
2038 AssertReturn(uIdx == 0, NULL); /* Only one transfer allowed at the moment. */
2039 return RTListGetFirst(&pURI->List, SHAREDCLIPBOARDURITRANSFER, Node);
2040}
2041
2042/**
2043 * Returns a specific URI transfer.
2044 *
2045 * @returns URI transfer, or NULL if not found.
2046 * @param pURI URI clipboard context to return transfer for.
2047 * @param uIdx Index of the transfer to return.
2048 */
2049PSHAREDCLIPBOARDURITRANSFER SharedClipboardURICtxGetTransfer(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
2050{
2051 return sharedClipboardURICtxGetTransferInternal(pURI, uIdx);
2052}
2053
2054/**
2055 * Returns the number of active URI transfers.
2056 *
2057 * @returns VBox status code.
2058 * @param pURI URI clipboard context to return number for.
2059 */
2060uint32_t SharedClipboardURICtxGetActiveTransfers(PSHAREDCLIPBOARDURICTX pURI)
2061{
2062 AssertPtrReturn(pURI, 0);
2063 return pURI->cTransfers;
2064}
2065
2066/**
2067 * Returns whether the maximum of concurrent transfers of a specific URI context has been reached or not.
2068 *
2069 * @returns \c if maximum has been reached, \c false if not.
2070 * @param pURI URI clipboard context to determine value for.
2071 */
2072bool SharedClipboardURICtxMaximumTransfersReached(PSHAREDCLIPBOARDURICTX pURI)
2073{
2074 AssertPtrReturn(pURI, true);
2075
2076 LogFlowFunc(("cTransfers=%RU32\n", pURI->cTransfers));
2077
2078 Assert(pURI->cTransfers <= pURI->cMaxTransfers);
2079 return pURI->cTransfers == pURI->cMaxTransfers;
2080}
2081#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
2082
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