VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/ClipboardProvider.cpp@ 79366

Last change on this file since 79366 was 79299, checked in by vboxsync, 5 years ago

Shared Clipboard/URI: Update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.9 KB
Line 
1/* $Id: ClipboardProvider.cpp 79299 2019-06-24 10:18:19Z vboxsync $ */
2/** @file
3 * Shared Clipboard - Provider base class implementation.
4 */
5
6/*
7 * Copyright (C) 2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
23#include <VBox/GuestHost/SharedClipboard-uri.h>
24
25#include <iprt/asm.h>
26#include <iprt/assert.h>
27#include <iprt/dir.h>
28#include <iprt/errcore.h>
29#include <iprt/file.h>
30#include <iprt/path.h>
31#include <iprt/semaphore.h>
32#include <iprt/string.h>
33
34#include <VBox/log.h>
35
36
37SharedClipboardProvider::Event::Event(uint32_t uMsg)
38 : mMsg(uMsg)
39 , mpvData(NULL)
40 , mcbData(0)
41{
42 int rc2 = RTSemEventCreate(&mEvent);
43 AssertRC(rc2);
44}
45
46SharedClipboardProvider::Event::~Event()
47{
48 Reset();
49
50 int rc2 = RTSemEventDestroy(mEvent);
51 AssertRC(rc2);
52}
53
54/**
55 * Resets an event by clearing the (allocated) data.
56 */
57void SharedClipboardProvider::Event::Reset(void)
58{
59 LogFlowFuncEnter();
60
61 if (mpvData)
62 {
63 Assert(mcbData);
64
65 RTMemFree(mpvData);
66 mpvData = NULL;
67 }
68
69 mcbData = 0;
70}
71
72/**
73 * Sets user data associated to an event.
74 *
75 * @returns VBox status code.
76 * @param pvData Pointer to user data to set.
77 * @param cbData Size (in bytes) of user data to set.
78 */
79int SharedClipboardProvider::Event::SetData(const void *pvData, uint32_t cbData)
80{
81 Reset();
82
83 if (!cbData)
84 return VINF_SUCCESS;
85
86 mpvData = RTMemDup(pvData, cbData);
87 if (!mpvData)
88 return VERR_NO_MEMORY;
89
90 mcbData = cbData;
91
92 return VINF_SUCCESS;
93}
94
95/**
96 * Waits for an event to get signalled.
97 * Will return VERR_NOT_FOUND if no event has been found.
98 *
99 * @returns VBox status code.
100 * @param uTimeoutMs Timeout (in ms) to wait.
101 */
102int SharedClipboardProvider::Event::Wait(RTMSINTERVAL uTimeoutMs)
103{
104 LogFlowFunc(("mMsg=%RU32, uTimeoutMs=%RU32\n", mMsg, uTimeoutMs));
105
106 int rc = RTSemEventWait(mEvent, uTimeoutMs);
107
108 LogFlowFuncLeaveRC(rc);
109 return rc;
110}
111
112/**
113 * Lets the caller adopt (transfer ownership) the returned event data.
114 * The caller is responsible of free'ing the data accordingly.
115 *
116 * @returns Pointer to the adopted event's raw data.
117 */
118void *SharedClipboardProvider::Event::DataAdopt(void)
119{
120 void *pvData = mpvData;
121
122 mpvData = NULL;
123 mcbData = 0;
124
125 return pvData;
126}
127
128/**
129 * Returns the event's (raw) data (mutable).
130 *
131 * @returns Pointer to the event's raw data.
132 */
133void *SharedClipboardProvider::Event::DataRaw(void)
134{
135 return mpvData;
136}
137
138/**
139 * Returns the event's data size (in bytes).
140 *
141 * @returns Data size (in bytes).
142 */
143uint32_t SharedClipboardProvider::Event::DataSize(void)
144{
145 return mcbData;
146}
147
148SharedClipboardProvider::SharedClipboardProvider(void)
149 : m_cRefs(0)
150 , m_enmDir(SHAREDCLIPBOARDURITRANSFERDIR_UNKNOWN)
151 , m_uTimeoutMs(30 * 1000 /* 30s timeout by default */)
152{
153 LogFlowFuncEnter();
154}
155
156SharedClipboardProvider::~SharedClipboardProvider(void)
157{
158 LogFlowFuncEnter();
159
160 Assert(m_cRefs == 0);
161
162 eventUnregisterAll();
163}
164
165/**
166 * Creates a Shared Clipboard provider.
167 *
168 * @returns New Shared Clipboard provider instance.
169 * @param pCtx Pointer to creation context.
170 */
171/* static */
172SharedClipboardProvider *SharedClipboardProvider::Create(PSHAREDCLIPBOARDPROVIDERCREATIONCTX pCtx)
173{
174 AssertPtrReturn(pCtx, NULL);
175
176 SharedClipboardProvider *pProvider = NULL;
177
178 switch (pCtx->enmSource)
179 {
180#ifdef VBOX_WITH_SHARED_CLIPBOARD_GUEST
181 case SHAREDCLIPBOARDURIPROVIDERSOURCE_VBGLR3:
182 pProvider = new SharedClipboardProviderVbglR3(pCtx->u.VbglR3.uClientID);
183 break;
184#endif
185
186#ifdef VBOX_WITH_SHARED_CLIPBOARD_HOST
187 case SHAREDCLIPBOARDURIPROVIDERSOURCE_HOSTSERVICE:
188 pProvider = new SharedClipboardProviderHostService(pCtx->u.HostService.pArea);
189 break;
190#endif
191 default:
192 AssertFailed();
193 break;
194 }
195
196 if (pProvider)
197 pProvider->SetCallbacks(pCtx->pCallbacks);
198
199 return pProvider;
200}
201
202/**
203 * Adds a reference to a Shared Clipboard provider.
204 *
205 * @returns New reference count.
206 */
207uint32_t SharedClipboardProvider::AddRef(void)
208{
209 LogFlowFuncEnter();
210 return ASMAtomicIncU32(&m_cRefs);
211}
212
213/**
214 * Removes a reference from a Shared Clipboard cache.
215 *
216 * @returns New reference count.
217 */
218uint32_t SharedClipboardProvider::Release(void)
219{
220 LogFlowFuncEnter();
221 Assert(m_cRefs);
222 return ASMAtomicDecU32(&m_cRefs);
223}
224
225/**
226 * Sets or unsets the callback table to be used for a clipboard provider.
227 *
228 * @returns VBox status code.
229 * @param pCallbacks Pointer to callback table to set. Specify NULL to unset existing callbacks.
230 */
231void SharedClipboardProvider::SetCallbacks(PSHAREDCLIPBOARDPROVIDERCALLBACKS pCallbacks)
232{
233 /* pCallbacks might be NULL to unset callbacks. */
234
235 LogFlowFunc(("pCallbacks=%p\n", pCallbacks));
236
237 if (pCallbacks)
238 {
239 m_Callbacks = *pCallbacks;
240 }
241 else
242 RT_ZERO(m_Callbacks);
243}
244
245/*
246 * Stubs.
247 */
248
249int SharedClipboardProvider::Prepare(void)
250{
251 return VINF_SUCCESS;
252}
253
254int SharedClipboardProvider::ReadDataHdr(PVBOXCLIPBOARDDATAHDR *ppDataHdr)
255{
256 RT_NOREF(ppDataHdr);
257 return VERR_NOT_IMPLEMENTED;
258}
259
260int SharedClipboardProvider::WriteDataHdr(const PVBOXCLIPBOARDDATAHDR pDataHdr)
261{
262 RT_NOREF(pDataHdr);
263 return VERR_NOT_IMPLEMENTED;
264}
265
266int SharedClipboardProvider::ReadDataChunk(const PVBOXCLIPBOARDDATAHDR pDataHdr, void *pvChunk, uint32_t cbChunk,
267 uint32_t fFlags /* = 0 */, uint32_t *pcbRead /* = NULL*/)
268{
269 RT_NOREF(pDataHdr, pvChunk, cbChunk, fFlags, pcbRead);
270 return VERR_NOT_IMPLEMENTED;
271}
272
273int SharedClipboardProvider::WriteDataChunk(const PVBOXCLIPBOARDDATAHDR pDataHdr, const void *pvChunk, uint32_t cbChunk,
274 uint32_t fFlags /* = 0 */, uint32_t *pcbWritten /* = NULL */)
275{
276 RT_NOREF(pDataHdr, pvChunk, cbChunk, fFlags, pcbWritten);
277 return VERR_NOT_IMPLEMENTED;
278}
279
280int SharedClipboardProvider::ReadDirectory(PVBOXCLIPBOARDDIRDATA *ppDirData)
281{
282 RT_NOREF(ppDirData);
283
284 LogFlowFuncEnter();
285
286 int rc = VERR_NOT_IMPLEMENTED;
287
288 LogFlowFuncLeaveRC(rc);
289 return rc;
290}
291
292int SharedClipboardProvider::WriteDirectory(const PVBOXCLIPBOARDDIRDATA pDirData)
293{
294 RT_NOREF(pDirData);
295
296 LogFlowFuncEnter();
297
298 int rc = VERR_NOT_IMPLEMENTED;
299
300 LogFlowFuncLeaveRC(rc);
301 return rc;
302}
303
304int SharedClipboardProvider::ReadFileHdr(PVBOXCLIPBOARDFILEHDR *ppFileHdr)
305{
306 RT_NOREF(ppFileHdr);
307
308 LogFlowFuncEnter();
309
310 int rc = VERR_NOT_IMPLEMENTED;
311
312 LogFlowFuncLeaveRC(rc);
313 return rc;
314}
315
316int SharedClipboardProvider::WriteFileHdr(const PVBOXCLIPBOARDFILEHDR pFileHdr)
317{
318 RT_NOREF(pFileHdr);
319
320 LogFlowFuncEnter();
321
322 int rc = VERR_NOT_IMPLEMENTED;
323
324 LogFlowFuncLeaveRC(rc);
325 return rc;
326}
327
328int SharedClipboardProvider::ReadFileData(void *pvData, uint32_t cbData, uint32_t fFlags /* = 0 */,
329 uint32_t *pcbRead /* = NULL */)
330{
331 RT_NOREF(pvData, cbData, fFlags, pcbRead);
332
333 LogFlowFuncEnter();
334
335 int rc = VERR_NOT_IMPLEMENTED;
336
337 LogFlowFuncLeaveRC(rc);
338 return rc;
339}
340
341int SharedClipboardProvider::WriteFileData(void *pvData, uint32_t cbData, uint32_t fFlags /* = 0 */,
342 uint32_t *pcbWritten /* = NULL */)
343{
344 RT_NOREF(pvData, cbData, fFlags, pcbWritten);
345
346 LogFlowFuncEnter();
347
348 int rc = VERR_NOT_IMPLEMENTED;
349
350 LogFlowFuncLeaveRC(rc);
351 return rc;
352}
353
354void SharedClipboardProvider::Reset(void)
355{
356}
357
358int SharedClipboardProvider::OnRead(PSHAREDCLIPBOARDPROVIDERREADPARMS pParms)
359{
360 RT_NOREF(pParms);
361
362 int rc = VERR_NOT_IMPLEMENTED;
363
364 LogFlowFuncLeaveRC(rc);
365 return rc;
366}
367
368int SharedClipboardProvider::OnWrite(PSHAREDCLIPBOARDPROVIDERWRITEPARMS pParms)
369{
370 RT_NOREF(pParms);
371
372 int rc = VERR_NOT_IMPLEMENTED;
373
374 LogFlowFuncLeaveRC(rc);
375 return rc;
376}
377
378/**
379 * Registers a new event.
380 * Will fail if an event with the same message ID already exists.
381 *
382 * @returns VBox status code.
383 * @param uMsg Message ID to register event for.
384 */
385int SharedClipboardProvider::eventRegister(uint32_t uMsg)
386{
387 LogFlowFunc(("uMsg=%RU32\n", uMsg));
388
389 int rc;
390
391 EventMap::const_iterator itEvent = m_mapEvents.find(uMsg);
392 if (itEvent == m_mapEvents.end())
393 {
394 SharedClipboardProvider::Event *pEvent = new SharedClipboardProvider::Event(uMsg);
395 if (pEvent) /** @todo Can this throw? */
396 {
397 m_mapEvents[uMsg] = pEvent; /** @todo Ditto. */
398
399 rc = VINF_SUCCESS;
400 }
401 else
402 rc = VERR_NO_MEMORY;
403 }
404 else
405 rc = VERR_ALREADY_EXISTS;
406
407 LogFlowFuncLeaveRC(rc);
408 return rc;
409}
410
411/**
412 * Unregisters an existing event.
413 * Will return VERR_NOT_FOUND if no event has been found.
414 *
415 * @returns VBox status code.
416 * @param uMsg Message ID to unregister event for.
417 */
418int SharedClipboardProvider::eventUnregister(uint32_t uMsg)
419{
420 LogFlowFunc(("uMsg=%RU32\n", uMsg));
421
422 int rc;
423
424 EventMap::const_iterator itEvent = m_mapEvents.find(uMsg);
425 if (itEvent != m_mapEvents.end())
426 {
427 delete itEvent->second;
428 m_mapEvents.erase(itEvent);
429
430 rc = VINF_SUCCESS;
431 }
432 else
433 rc = VERR_NOT_FOUND;
434
435 LogFlowFuncLeaveRC(rc);
436 return rc;
437}
438
439/**
440 * Unregisters all registered events.
441 *
442 * @returns VBox status code.
443 */
444int SharedClipboardProvider::eventUnregisterAll(void)
445{
446 int rc = VINF_SUCCESS;
447
448 LogFlowFuncEnter();
449
450 EventMap::const_iterator itEvent = m_mapEvents.begin();
451 while (itEvent != m_mapEvents.end())
452 {
453 delete itEvent->second;
454 m_mapEvents.erase(itEvent);
455
456 itEvent = m_mapEvents.begin();
457 }
458
459 LogFlowFuncLeaveRC(rc);
460 return rc;
461}
462
463/**
464 * Signals an event.
465 * Will return VERR_NOT_FOUND if no event has been found.
466 *
467 * @returns VBox status code.
468 * @param uMsg Message ID of event to signal.
469 */
470int SharedClipboardProvider::eventSignal(uint32_t uMsg)
471{
472 LogFlowFunc(("uMsg=%RU32\n", uMsg));
473
474 int rc;
475
476 EventMap::const_iterator itEvent = m_mapEvents.find(uMsg);
477 if (itEvent != m_mapEvents.end())
478 {
479 rc = RTSemEventSignal(itEvent->second->mEvent);
480 }
481 else
482 rc = VERR_NOT_FOUND;
483
484 LogFlowFuncLeaveRC(rc);
485 return rc;
486}
487
488/**
489 * Returns the event for a specific message ID.
490 *
491 * @returns Pointer to event if found, or NULL if no event has been found
492 * @param uMsg Messagae ID to return event for.
493 */
494SharedClipboardProvider::Event *SharedClipboardProvider::eventGet(uint32_t uMsg)
495{
496 LogFlowFuncEnter();
497
498 EventMap::const_iterator itEvent = m_mapEvents.find(uMsg);
499 if (itEvent != m_mapEvents.end())
500 return itEvent->second;
501
502 return NULL;
503}
504
505/**
506 * Waits for an event to get signalled and optionally returns related event data on success.
507 *
508 * @returns VBox status code.
509 * @param uMsg Message ID of event to wait for.
510 * @param pfnCallback Callback to use before waiting for event. Specify NULL if not needed.
511 * @param uTimeoutMs Timeout (in ms) to wait for.
512 * @param ppvData Where to store the related event data. Optioanl.
513 * @param pcbData Where to store the size (in bytes) of the related event data. Optioanl.
514 */
515int SharedClipboardProvider::eventWait(uint32_t uMsg, PFNSSHAREDCLIPBOARDPROVIDERCALLBACK pfnCallback,
516 RTMSINTERVAL uTimeoutMs, void **ppvData, uint32_t *pcbData /* = NULL */)
517{
518 LogFlowFunc(("uMsg=%RU32, uTimeoutMs=%RU32\n", uMsg, uTimeoutMs));
519
520 int rc = VINF_SUCCESS;
521
522 if (pfnCallback)
523 {
524 SHAREDCLIPBOARDPROVIDERCALLBACKDATA data = { this, m_Callbacks.pvUser };
525 rc = pfnCallback(&data);
526 }
527
528 if (RT_SUCCESS(rc))
529 {
530 Event *pEvent = eventGet(uMsg);
531 if (pEvent)
532 {
533 rc = pEvent->Wait(m_uTimeoutMs);
534 if (RT_SUCCESS(rc))
535 {
536 if (pcbData)
537 *pcbData = pEvent->DataSize();
538
539 if (ppvData)
540 *ppvData = pEvent->DataAdopt();
541
542 pEvent->Reset();
543 }
544 }
545 else
546 rc = VERR_NOT_FOUND;
547 }
548
549 LogFlowFuncLeaveRC(rc);
550 return rc;
551}
552
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