VirtualBox

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

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

Shared Clipboard/URI: Update.

  • Property eol-style set to native
  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 18.8 KB
Line 
1/* $Id: clipboard-common.cpp 78974 2019-06-04 16:51:48Z 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#include <iprt/alloc.h>
21#include <iprt/assert.h>
22#include <iprt/errcore.h>
23
24#include <VBox/log.h>
25#include <VBox/GuestHost/clipboard-helper.h>
26#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
27# include <VBox/GuestHost/SharedClipboard-uri.h>
28#endif
29
30
31/** @todo use const where appropriate; delinuxify the code (*Lin* -> *Host*); use AssertLogRel*. */
32
33int vboxClipboardUtf16GetWinSize(PRTUTF16 pwszSrc, size_t cwSrc, size_t *pcwDest)
34{
35 size_t cwDest, i;
36
37 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
38 AssertLogRelMsgReturn(pwszSrc != NULL, ("vboxClipboardUtf16GetWinSize: received a null Utf16 string, returning VERR_INVALID_PARAMETER\n"), VERR_INVALID_PARAMETER);
39 if (cwSrc == 0)
40 {
41 *pcwDest = 0;
42 LogFlowFunc(("empty source string, returning\n"));
43 return VINF_SUCCESS;
44 }
45/** @todo convert the remainder of the Assert stuff to AssertLogRel. */
46 /* We only take little endian Utf16 */
47 if (pwszSrc[0] == UTF16BEMARKER)
48 {
49 LogRel(("vboxClipboardUtf16GetWinSize: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
50 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
51 }
52 cwDest = 0;
53 /* Calculate the size of the destination text string. */
54 /* Is this Utf16 or Utf16-LE? */
55 for (i = (pwszSrc[0] == UTF16LEMARKER ? 1 : 0); i < cwSrc; ++i, ++cwDest)
56 {
57 /* Check for a single line feed */
58 if (pwszSrc[i] == LINEFEED)
59 ++cwDest;
60#ifdef RT_OS_DARWIN
61 /* Check for a single carriage return (MacOS) */
62 if (pwszSrc[i] == CARRIAGERETURN)
63 ++cwDest;
64#endif
65 if (pwszSrc[i] == 0)
66 {
67 /* Don't count this, as we do so below. */
68 break;
69 }
70 }
71 /* Count the terminating null byte. */
72 ++cwDest;
73 LogFlowFunc(("returning VINF_SUCCESS, %d 16bit words\n", cwDest));
74 *pcwDest = cwDest;
75 return VINF_SUCCESS;
76}
77
78int vboxClipboardUtf16LinToWin(PRTUTF16 pwszSrc, size_t cwSrc, PRTUTF16 pu16Dest,
79 size_t cwDest)
80{
81 size_t i, j;
82 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
83 if (!VALID_PTR(pwszSrc) || !VALID_PTR(pu16Dest))
84 {
85 LogRel(("vboxClipboardUtf16LinToWin: received an invalid pointer, pwszSrc=%p, pu16Dest=%p, returning VERR_INVALID_PARAMETER\n", pwszSrc, pu16Dest));
86 AssertReturn(VALID_PTR(pwszSrc) && VALID_PTR(pu16Dest), VERR_INVALID_PARAMETER);
87 }
88 if (cwSrc == 0)
89 {
90 if (cwDest == 0)
91 {
92 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
93 return VERR_BUFFER_OVERFLOW;
94 }
95 pu16Dest[0] = 0;
96 LogFlowFunc(("empty source string, returning\n"));
97 return VINF_SUCCESS;
98 }
99 /* We only take little endian Utf16 */
100 if (pwszSrc[0] == UTF16BEMARKER)
101 {
102 LogRel(("vboxClipboardUtf16LinToWin: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
103 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
104 }
105 /* Don't copy the endian marker. */
106 for (i = (pwszSrc[0] == UTF16LEMARKER ? 1 : 0), j = 0; i < cwSrc; ++i, ++j)
107 {
108 /* Don't copy the null byte, as we add it below. */
109 if (pwszSrc[i] == 0)
110 break;
111 if (j == cwDest)
112 {
113 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
114 return VERR_BUFFER_OVERFLOW;
115 }
116 if (pwszSrc[i] == LINEFEED)
117 {
118 pu16Dest[j] = CARRIAGERETURN;
119 ++j;
120 if (j == cwDest)
121 {
122 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
123 return VERR_BUFFER_OVERFLOW;
124 }
125 }
126#ifdef RT_OS_DARWIN
127 /* Check for a single carriage return (MacOS) */
128 else if (pwszSrc[i] == CARRIAGERETURN)
129 {
130 /* set cr */
131 pu16Dest[j] = CARRIAGERETURN;
132 ++j;
133 if (j == cwDest)
134 {
135 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
136 return VERR_BUFFER_OVERFLOW;
137 }
138 /* add the lf */
139 pu16Dest[j] = LINEFEED;
140 continue;
141 }
142#endif
143 pu16Dest[j] = pwszSrc[i];
144 }
145 /* Add the trailing null. */
146 if (j == cwDest)
147 {
148 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
149 return VERR_BUFFER_OVERFLOW;
150 }
151 pu16Dest[j] = 0;
152 LogFlowFunc(("rc=VINF_SUCCESS, pu16Dest=%ls\n", pu16Dest));
153 return VINF_SUCCESS;
154}
155
156int vboxClipboardUtf16GetLinSize(PRTUTF16 pwszSrc, size_t cwSrc, size_t *pcwDest)
157{
158 size_t cwDest;
159
160 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
161 if (!VALID_PTR(pwszSrc))
162 {
163 LogRel(("vboxClipboardUtf16GetLinSize: received an invalid Utf16 string %p. Returning VERR_INVALID_PARAMETER.\n", pwszSrc));
164 AssertReturn(VALID_PTR(pwszSrc), VERR_INVALID_PARAMETER);
165 }
166 if (cwSrc == 0)
167 {
168 LogFlowFunc(("empty source string, returning VINF_SUCCESS\n"));
169 *pcwDest = 0;
170 return VINF_SUCCESS;
171 }
172 /* We only take little endian Utf16 */
173 if (pwszSrc[0] == UTF16BEMARKER)
174 {
175 LogRel(("vboxClipboardUtf16GetLinSize: received a big endian Utf16 string. Returning VERR_INVALID_PARAMETER.\n"));
176 AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
177 }
178 /* Calculate the size of the destination text string. */
179 /* Is this Utf16 or Utf16-LE? */
180 if (pwszSrc[0] == UTF16LEMARKER)
181 cwDest = 0;
182 else
183 cwDest = 1;
184 for (size_t i = 0; i < cwSrc; ++i, ++cwDest)
185 {
186 if ( (i + 1 < cwSrc)
187 && (pwszSrc[i] == CARRIAGERETURN)
188 && (pwszSrc[i + 1] == LINEFEED))
189 {
190 ++i;
191 }
192 if (pwszSrc[i] == 0)
193 {
194 break;
195 }
196 }
197 /* Terminating zero */
198 ++cwDest;
199 LogFlowFunc(("returning %d\n", cwDest));
200 *pcwDest = cwDest;
201 return VINF_SUCCESS;
202}
203
204int vboxClipboardUtf16WinToLin(PRTUTF16 pwszSrc, size_t cwSrc, PRTUTF16 pu16Dest,
205 size_t cwDest)
206{
207 size_t cwDestPos;
208
209 LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u, pu16Dest=%p, cwDest=%u\n",
210 cwSrc, pwszSrc, cwSrc, pu16Dest, cwDest));
211 /* A buffer of size 0 may not be an error, but it is not a good idea either. */
212 Assert(cwDest > 0);
213 if (!VALID_PTR(pwszSrc) || !VALID_PTR(pu16Dest))
214 {
215 LogRel(("vboxClipboardUtf16WinToLin: received an invalid ptr, pwszSrc=%p, pu16Dest=%p, returning VERR_INVALID_PARAMETER\n", pwszSrc, pu16Dest));
216 AssertReturn(VALID_PTR(pwszSrc) && VALID_PTR(pu16Dest), VERR_INVALID_PARAMETER);
217 }
218 /* We only take little endian Utf16 */
219 if (pwszSrc[0] == UTF16BEMARKER)
220 {
221 LogRel(("vboxClipboardUtf16WinToLin: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
222 AssertMsgFailedReturn(("received a big endian string\n"), VERR_INVALID_PARAMETER);
223 }
224 if (cwDest == 0)
225 {
226 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
227 return VERR_BUFFER_OVERFLOW;
228 }
229 if (cwSrc == 0)
230 {
231 pu16Dest[0] = 0;
232 LogFlowFunc(("received empty string. Returning VINF_SUCCESS\n"));
233 return VINF_SUCCESS;
234 }
235 /* Prepend the Utf16 byte order marker if it is missing. */
236 if (pwszSrc[0] == UTF16LEMARKER)
237 {
238 cwDestPos = 0;
239 }
240 else
241 {
242 pu16Dest[0] = UTF16LEMARKER;
243 cwDestPos = 1;
244 }
245 for (size_t i = 0; i < cwSrc; ++i, ++cwDestPos)
246 {
247 if (pwszSrc[i] == 0)
248 {
249 break;
250 }
251 if (cwDestPos == cwDest)
252 {
253 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
254 return VERR_BUFFER_OVERFLOW;
255 }
256 if ( (i + 1 < cwSrc)
257 && (pwszSrc[i] == CARRIAGERETURN)
258 && (pwszSrc[i + 1] == LINEFEED))
259 {
260 ++i;
261 }
262 pu16Dest[cwDestPos] = pwszSrc[i];
263 }
264 /* Terminating zero */
265 if (cwDestPos == cwDest)
266 {
267 LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
268 return VERR_BUFFER_OVERFLOW;
269 }
270 pu16Dest[cwDestPos] = 0;
271 LogFlowFunc(("set string %ls. Returning\n", pu16Dest + 1));
272 return VINF_SUCCESS;
273}
274
275int vboxClipboardDibToBmp(const void *pvSrc, size_t cbSrc, void **ppvDest, size_t *pcbDest)
276{
277 size_t cb = sizeof(BMFILEHEADER) + cbSrc;
278 PBMFILEHEADER pFileHeader = NULL;
279 void *pvDest = NULL;
280 size_t offPixel = 0;
281
282 AssertPtrReturn(pvSrc, VERR_INVALID_PARAMETER);
283 AssertPtrReturn(ppvDest, VERR_INVALID_PARAMETER);
284 AssertPtrReturn(pcbDest, VERR_INVALID_PARAMETER);
285
286 PBMINFOHEADER pBitmapInfoHeader = (PBMINFOHEADER)pvSrc;
287 /** @todo Support all the many versions of the DIB headers. */
288 if ( cbSrc < sizeof(BMINFOHEADER)
289 || RT_LE2H_U32(pBitmapInfoHeader->u32Size) < sizeof(BMINFOHEADER)
290 || RT_LE2H_U32(pBitmapInfoHeader->u32Size) != sizeof(BMINFOHEADER))
291 {
292 Log(("vboxClipboardDibToBmp: invalid or unsupported bitmap data.\n"));
293 return VERR_INVALID_PARAMETER;
294 }
295
296 offPixel = sizeof(BMFILEHEADER)
297 + RT_LE2H_U32(pBitmapInfoHeader->u32Size)
298 + RT_LE2H_U32(pBitmapInfoHeader->u32ClrUsed) * sizeof(uint32_t);
299 if (cbSrc < offPixel)
300 {
301 Log(("vboxClipboardDibToBmp: invalid bitmap data.\n"));
302 return VERR_INVALID_PARAMETER;
303 }
304
305 pvDest = RTMemAlloc(cb);
306 if (!pvDest)
307 {
308 Log(("writeToPasteboard: cannot allocate memory for bitmap.\n"));
309 return VERR_NO_MEMORY;
310 }
311
312 pFileHeader = (PBMFILEHEADER)pvDest;
313 pFileHeader->u16Type = BITMAPHEADERMAGIC;
314 pFileHeader->u32Size = (uint32_t)RT_H2LE_U32(cb);
315 pFileHeader->u16Reserved1 = pFileHeader->u16Reserved2 = 0;
316 pFileHeader->u32OffBits = (uint32_t)RT_H2LE_U32(offPixel);
317 memcpy((uint8_t *)pvDest + sizeof(BMFILEHEADER), pvSrc, cbSrc);
318 *ppvDest = pvDest;
319 *pcbDest = cb;
320 return VINF_SUCCESS;
321}
322
323int vboxClipboardBmpGetDib(const void *pvSrc, size_t cbSrc, const void **ppvDest, size_t *pcbDest)
324{
325 AssertPtrReturn(pvSrc, VERR_INVALID_PARAMETER);
326 AssertPtrReturn(ppvDest, VERR_INVALID_PARAMETER);
327 AssertPtrReturn(pcbDest, VERR_INVALID_PARAMETER);
328
329 PBMFILEHEADER pFileHeader = (PBMFILEHEADER)pvSrc;
330 if ( cbSrc < sizeof(BMFILEHEADER)
331 || pFileHeader->u16Type != BITMAPHEADERMAGIC
332 || RT_LE2H_U32(pFileHeader->u32Size) != cbSrc)
333 {
334 Log(("vboxClipboardBmpGetDib: invalid bitmap data.\n"));
335 return VERR_INVALID_PARAMETER;
336 }
337
338 *ppvDest = ((uint8_t *)pvSrc) + sizeof(BMFILEHEADER);
339 *pcbDest = cbSrc - sizeof(BMFILEHEADER);
340 return VINF_SUCCESS;
341}
342
343#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
344/**
345 * Initializes an URI clipboard transfer struct.
346 *
347 * @returns VBox status code.
348 * @param pCtx Shared Clipboard provider creation context to use.
349 * @param ppTransfer Where to return the created URI transfer struct.
350 * Must be free'd by SharedClipboardURITransferDestroy().
351 */
352int SharedClipboardURITransferCreate(PSHAREDCLIPBOARDPROVIDERCREATIONCTX pCtx,
353 PSHAREDCLIPBOARDURITRANSFER *ppTransfer)
354{
355 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
356 AssertPtrReturn(ppTransfer, VERR_INVALID_POINTER);
357
358 PSHAREDCLIPBOARDURITRANSFER pTransfer = (PSHAREDCLIPBOARDURITRANSFER)RTMemAlloc(sizeof(SHAREDCLIPBOARDURITRANSFER));
359 if (!pTransfer)
360 return VERR_NO_MEMORY;
361
362 LogFlowFuncEnter();
363
364 pTransfer->pProvider = SharedClipboardProvider::Create(pCtx);
365 if (!pTransfer->pProvider)
366 return VERR_NO_MEMORY;
367
368 pTransfer->Thread.fCancelled = false;
369 pTransfer->Thread.fStarted = false;
370
371 pTransfer->pvUser = NULL;
372 pTransfer->cbUser = 0;
373
374 *ppTransfer = pTransfer;
375
376 return VINF_SUCCESS;
377}
378
379/**
380 * Destroys an URI clipboard transfer context struct.
381 *
382 * @param pURI URI clipboard transfer struct to destroy.
383 */
384void SharedClipboardURITransferDestroy(PSHAREDCLIPBOARDURITRANSFER pTransfer)
385{
386 if (!pTransfer)
387 return;
388
389 LogFlowFuncEnter();
390
391 if (pTransfer->pProvider)
392 {
393 delete pTransfer->pProvider;
394 pTransfer->pProvider = NULL;
395 }
396
397 RTMemFree(pTransfer);
398 pTransfer = NULL;
399}
400
401/**
402 * Resets an URI clipboard context struct.
403 *
404 * @param pTransfer URI clipboard transfer struct to reset.
405 */
406void SharedClipboardURITransferReset(PSHAREDCLIPBOARDURITRANSFER pTransfer)
407{
408 AssertPtrReturnVoid(pTransfer);
409
410 LogFlowFuncEnter();
411
412 if (pTransfer->pProvider)
413 pTransfer->pProvider->Reset();
414}
415
416/**
417 * Writes all URI objects using the connected provider.
418 *
419 * @returns VBox status code.
420 * @param pTransfer Transfer to write objects for.
421 */
422int SharedClipboardURITransferWrite(PSHAREDCLIPBOARDURITRANSFER pTransfer)
423{
424 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
425
426 LogFlowFuncEnter();
427
428 int rc = VINF_SUCCESS;
429
430 SharedClipboardURIList &lstURI = pTransfer->pProvider->GetURIList();
431
432 while (!lstURI.IsEmpty())
433 {
434 SharedClipboardURIObject *pObj = lstURI.First();
435 AssertPtrBreakStmt(pObj, rc = VERR_INVALID_POINTER);
436
437 switch (pObj->GetType())
438 {
439 case SharedClipboardURIObject::Type_Directory:
440 {
441 rc = pTransfer->pProvider->WriteDirectoryObj(*pObj);
442 break;
443 }
444
445 case SharedClipboardURIObject::Type_File:
446 {
447 rc = pTransfer->pProvider->WriteFileHdrObj(*pObj);
448 if (RT_FAILURE(rc))
449 break;
450
451 while (!pObj->IsComplete())
452 {
453 uint32_t cbWritten;
454 rc = pTransfer->pProvider->WriteFileDataObj(*pObj, &cbWritten);
455 if (RT_FAILURE(rc))
456 break;
457 }
458 break;
459 }
460
461 default:
462 AssertFailed();
463 break;
464 }
465
466 if (RT_FAILURE(rc))
467 break;
468
469 /* Only remove current object on success. */
470 lstURI.RemoveFirst();
471 }
472
473 LogFlowFuncLeaveRC(rc);
474 return rc;
475}
476
477/**
478 * Thread for transferring (writing) URI objects from source to the target.
479 * For target to source transfers we utilize our own IDataObject / IStream implementations.
480 *
481 * @returns VBox status code.
482 * @param hThread Thread handle.
483 * @param pvUser User arguments; is PSHAREDCLIPBOARDURICTX.
484 */
485int SharedClipboardURITransferWriteThread(RTTHREAD hThread, void *pvUser)
486{
487 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
488
489 LogFlowFuncEnter();
490
491 PSHAREDCLIPBOARDURICTX pURICtx = (PSHAREDCLIPBOARDURICTX)pvUser;
492 AssertPtr(pURICtx);
493
494 /* At the moment we only support one transfer at a time. */
495 PSHAREDCLIPBOARDURITRANSFER pTransfer = SharedClipboardURICtxGetTransfer(pURICtx, 0 /* Index*/);
496 AssertPtr(pTransfer->pProvider);
497
498 int rc = VINF_SUCCESS;
499
500 if (RT_SUCCESS(rc))
501 pTransfer->Thread.fStarted = true;
502
503 int rc2 = RTThreadUserSignal(hThread);
504 const bool fSignalled = RT_SUCCESS(rc2);
505
506 if (RT_SUCCESS(rc))
507 rc = SharedClipboardURITransferWrite(pTransfer);
508
509 if (!fSignalled)
510 {
511 rc2 = RTThreadUserSignal(hThread);
512 AssertRC(rc2);
513 }
514
515 LogFlowFuncLeaveRC(rc);
516 return rc;
517}
518
519/**
520 * Initializes an URI clipboard context struct.
521 *
522 * @returns VBox status code.
523 * @param pURI URI clipboard context to initialize.
524 * @param pTransfer Pointer to URI clipboard transfer struct to use.
525 */
526int SharedClipboardURICtxInit(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
527{
528 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
529 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
530
531 LogFlowFuncEnter();
532
533 int rc = RTCritSectInit(&pURI->CritSect);
534 if (RT_SUCCESS(rc))
535 {
536 RTListInit(&pURI->List);
537
538 SharedClipboardURICtxReset(pURI);
539 }
540
541 return VINF_SUCCESS;
542}
543
544/**
545 * Destroys an URI clipboard information context struct.
546 *
547 * @param pURI URI clipboard context to destroy.
548 */
549void SharedClipboardURICtxDestroy(PSHAREDCLIPBOARDURICTX pURI)
550{
551 AssertPtrReturnVoid(pURI);
552
553 RTCritSectDelete(&pURI->CritSect);
554
555 PSHAREDCLIPBOARDURITRANSFER pTransfer, pTransferNext;
556 RTListForEachSafe(&pURI->List, pTransfer, pTransferNext, SHAREDCLIPBOARDURITRANSFER, Node)
557 {
558 SharedClipboardURITransferDestroy(pTransfer);
559 RTListNodeRemove(&pTransfer->Node);
560 }
561
562 LogFlowFuncEnter();
563}
564
565/**
566 * Resets an URI clipboard context struct.
567 *
568 * @param pURI URI clipboard context to reset.
569 */
570void SharedClipboardURICtxReset(PSHAREDCLIPBOARDURICTX pURI)
571{
572 AssertPtrReturnVoid(pURI);
573
574 LogFlowFuncEnter();
575
576 pURI->cTransfers = 0;
577
578 PSHAREDCLIPBOARDURITRANSFER pTransfer;
579 RTListForEach(&pURI->List, pTransfer, SHAREDCLIPBOARDURITRANSFER, Node)
580 SharedClipboardURITransferReset(pTransfer);
581}
582
583/**
584 * Adds a new transfer to an URI clipboard context struct.
585 *
586 * @returns VBox status code.
587 * @param pURI URI clipboard context to add transfer to.
588 * @param pTransfer Pointer to URI clipboard transfer struct to add.
589 */
590int SharedClipboardURICtxTransferAdd(PSHAREDCLIPBOARDURICTX pURI, PSHAREDCLIPBOARDURITRANSFER pTransfer)
591{
592 AssertPtrReturn(pURI, VERR_INVALID_POINTER);
593 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
594
595 LogFlowFuncEnter();
596
597 RTListAppend(&pURI->List, &pTransfer->Node);
598
599 return VINF_SUCCESS;
600}
601
602/**
603 * Returns a specific URI transfer.
604 *
605 * @returns URI transfer, or NULL if not found.
606 * @param pURI URI clipboard context to return transfer for.
607 * @param uIdx Index of the transfer to return.
608 */
609PSHAREDCLIPBOARDURITRANSFER SharedClipboardURICtxGetTransfer(PSHAREDCLIPBOARDURICTX pURI, uint32_t uIdx)
610{
611 AssertReturn(uIdx == 0, NULL); /* Only one transfer allowed at the moment. */
612 return RTListGetFirst(&pURI->List, SHAREDCLIPBOARDURITRANSFER, Node);
613}
614
615/**
616 * Returns the number of active URI transfers.
617 *
618 * @returns VBox status code.
619 * @param pURI URI clipboard context to return number for.
620 */
621uint32_t SharedClipboardURICtxGetActiveTransfers(PSHAREDCLIPBOARDURICTX pURI)
622{
623 return pURI->cTransfers;
624}
625#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
626
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