VirtualBox

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

Last change on this file since 79267 was 79267, checked in by vboxsync, 6 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.7 KB
Line 
1/* $Id: ClipboardProvider.cpp 79267 2019-06-21 10:11:59Z 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_uTimeoutMs(30 * 1000 /* 30s timeout by default */)
151{
152 LogFlowFuncEnter();
153}
154
155SharedClipboardProvider::~SharedClipboardProvider(void)
156{
157 LogFlowFuncEnter();
158
159 Assert(m_cRefs == 0);
160
161 eventUnregisterAll();
162}
163
164/**
165 * Creates a Shared Clipboard provider.
166 *
167 * @returns New Shared Clipboard provider instance.
168 * @param pCtx Pointer to creation context.
169 */
170/* static */
171SharedClipboardProvider *SharedClipboardProvider::Create(PSHAREDCLIPBOARDPROVIDERCREATIONCTX pCtx)
172{
173 AssertPtrReturn(pCtx, NULL);
174
175 SharedClipboardProvider *pProvider = NULL;
176
177 switch (pCtx->enmSource)
178 {
179#ifdef VBOX_WITH_SHARED_CLIPBOARD_GUEST
180 case SHAREDCLIPBOARDPROVIDERSOURCE_VBGLR3:
181 pProvider = new SharedClipboardProviderVbglR3(pCtx->u.VbglR3.uClientID);
182 break;
183#endif
184
185#ifdef VBOX_WITH_SHARED_CLIPBOARD_HOST
186 case SHAREDCLIPBOARDPROVIDERSOURCE_HOSTSERVICE:
187 pProvider = new SharedClipboardProviderHostService(pCtx->u.HostService.pArea);
188 break;
189#endif
190 default:
191 AssertFailed();
192 break;
193 }
194
195 if (pProvider)
196 pProvider->SetCallbacks(pCtx->pCallbacks);
197
198 return pProvider;
199}
200
201/**
202 * Adds a reference to a Shared Clipboard provider.
203 *
204 * @returns New reference count.
205 */
206uint32_t SharedClipboardProvider::AddRef(void)
207{
208 LogFlowFuncEnter();
209 return ASMAtomicIncU32(&m_cRefs);
210}
211
212/**
213 * Removes a reference from a Shared Clipboard cache.
214 *
215 * @returns New reference count.
216 */
217uint32_t SharedClipboardProvider::Release(void)
218{
219 LogFlowFuncEnter();
220 Assert(m_cRefs);
221 return ASMAtomicDecU32(&m_cRefs);
222}
223
224/**
225 * Sets or unsets the callback table to be used for a clipboard provider.
226 *
227 * @returns VBox status code.
228 * @param pCallbacks Pointer to callback table to set. Specify NULL to unset existing callbacks.
229 */
230void SharedClipboardProvider::SetCallbacks(PSHAREDCLIPBOARDPROVIDERCALLBACKS pCallbacks)
231{
232 /* pCallbacks might be NULL to unset callbacks. */
233
234 LogFlowFunc(("pCallbacks=%p\n", pCallbacks));
235
236 if (pCallbacks)
237 {
238 m_Callbacks = *pCallbacks;
239 }
240 else
241 RT_ZERO(m_Callbacks);
242}
243
244/*
245 * Stubs.
246 */
247
248int SharedClipboardProvider::ReadDataHdr(PVBOXCLIPBOARDDATAHDR *ppDataHdr)
249{
250 RT_NOREF(ppDataHdr);
251 return VERR_NOT_IMPLEMENTED;
252}
253
254int SharedClipboardProvider::WriteDataHdr(const PVBOXCLIPBOARDDATAHDR pDataHdr)
255{
256 RT_NOREF(pDataHdr);
257 return VERR_NOT_IMPLEMENTED;
258}
259
260int SharedClipboardProvider::ReadDataChunk(const PVBOXCLIPBOARDDATAHDR pDataHdr, void *pvChunk, uint32_t cbChunk,
261 uint32_t fFlags /* = 0 */, uint32_t *pcbRead /* = NULL*/)
262{
263 RT_NOREF(pDataHdr, pvChunk, cbChunk, fFlags, pcbRead);
264 return VERR_NOT_IMPLEMENTED;
265}
266
267int SharedClipboardProvider::WriteDataChunk(const PVBOXCLIPBOARDDATAHDR pDataHdr, const void *pvChunk, uint32_t cbChunk,
268 uint32_t fFlags /* = 0 */, uint32_t *pcbWritten /* = NULL */)
269{
270 RT_NOREF(pDataHdr, pvChunk, cbChunk, fFlags, pcbWritten);
271 return VERR_NOT_IMPLEMENTED;
272}
273
274int SharedClipboardProvider::ReadDirectory(PVBOXCLIPBOARDDIRDATA *ppDirData)
275{
276 RT_NOREF(ppDirData);
277
278 LogFlowFuncEnter();
279
280 int rc = VERR_NOT_IMPLEMENTED;
281
282 LogFlowFuncLeaveRC(rc);
283 return rc;
284}
285
286int SharedClipboardProvider::WriteDirectory(const PVBOXCLIPBOARDDIRDATA pDirData)
287{
288 RT_NOREF(pDirData);
289
290 LogFlowFuncEnter();
291
292 int rc = VERR_NOT_IMPLEMENTED;
293
294 LogFlowFuncLeaveRC(rc);
295 return rc;
296}
297
298int SharedClipboardProvider::ReadFileHdr(PVBOXCLIPBOARDFILEHDR *ppFileHdr)
299{
300 RT_NOREF(ppFileHdr);
301
302 LogFlowFuncEnter();
303
304 int rc = VERR_NOT_IMPLEMENTED;
305
306 LogFlowFuncLeaveRC(rc);
307 return rc;
308}
309
310int SharedClipboardProvider::WriteFileHdr(const PVBOXCLIPBOARDFILEHDR pFileHdr)
311{
312 RT_NOREF(pFileHdr);
313
314 LogFlowFuncEnter();
315
316 int rc = VERR_NOT_IMPLEMENTED;
317
318 LogFlowFuncLeaveRC(rc);
319 return rc;
320}
321
322int SharedClipboardProvider::ReadFileData(void *pvData, uint32_t cbData, uint32_t fFlags /* = 0 */,
323 uint32_t *pcbRead /* = NULL */)
324{
325 RT_NOREF(pvData, cbData, fFlags, pcbRead);
326
327 LogFlowFuncEnter();
328
329 int rc = VERR_NOT_IMPLEMENTED;
330
331 LogFlowFuncLeaveRC(rc);
332 return rc;
333}
334
335int SharedClipboardProvider::WriteFileData(void *pvData, uint32_t cbData, uint32_t fFlags /* = 0 */,
336 uint32_t *pcbWritten /* = NULL */)
337{
338 RT_NOREF(pvData, cbData, fFlags, pcbWritten);
339
340 LogFlowFuncEnter();
341
342 int rc = VERR_NOT_IMPLEMENTED;
343
344 LogFlowFuncLeaveRC(rc);
345 return rc;
346}
347
348void SharedClipboardProvider::Reset(void)
349{
350}
351
352int SharedClipboardProvider::OnRead(PSHAREDCLIPBOARDPROVIDERREADPARMS pParms)
353{
354 RT_NOREF(pParms);
355
356 int rc = VERR_NOT_IMPLEMENTED;
357
358 LogFlowFuncLeaveRC(rc);
359 return rc;
360}
361
362int SharedClipboardProvider::OnWrite(PSHAREDCLIPBOARDPROVIDERWRITEPARMS pParms)
363{
364 RT_NOREF(pParms);
365
366 int rc = VERR_NOT_IMPLEMENTED;
367
368 LogFlowFuncLeaveRC(rc);
369 return rc;
370}
371
372/**
373 * Registers a new event.
374 * Will fail if an event with the same message ID already exists.
375 *
376 * @returns VBox status code.
377 * @param uMsg Message ID to register event for.
378 */
379int SharedClipboardProvider::eventRegister(uint32_t uMsg)
380{
381 LogFlowFunc(("uMsg=%RU32\n", uMsg));
382
383 int rc;
384
385 EventMap::const_iterator itEvent = m_mapEvents.find(uMsg);
386 if (itEvent == m_mapEvents.end())
387 {
388 SharedClipboardProvider::Event *pEvent = new SharedClipboardProvider::Event(uMsg);
389 if (pEvent) /** @todo Can this throw? */
390 {
391 m_mapEvents[uMsg] = pEvent; /** @todo Ditto. */
392
393 rc = VINF_SUCCESS;
394 }
395 else
396 rc = VERR_NO_MEMORY;
397 }
398 else
399 rc = VERR_ALREADY_EXISTS;
400
401 LogFlowFuncLeaveRC(rc);
402 return rc;
403}
404
405/**
406 * Unregisters an existing event.
407 * Will return VERR_NOT_FOUND if no event has been found.
408 *
409 * @returns VBox status code.
410 * @param uMsg Message ID to unregister event for.
411 */
412int SharedClipboardProvider::eventUnregister(uint32_t uMsg)
413{
414 LogFlowFunc(("uMsg=%RU32\n", uMsg));
415
416 int rc;
417
418 EventMap::const_iterator itEvent = m_mapEvents.find(uMsg);
419 if (itEvent != m_mapEvents.end())
420 {
421 delete itEvent->second;
422 m_mapEvents.erase(itEvent);
423
424 rc = VINF_SUCCESS;
425 }
426 else
427 rc = VERR_NOT_FOUND;
428
429 LogFlowFuncLeaveRC(rc);
430 return rc;
431}
432
433/**
434 * Unregisters all registered events.
435 *
436 * @returns VBox status code.
437 */
438int SharedClipboardProvider::eventUnregisterAll(void)
439{
440 int rc = VINF_SUCCESS;
441
442 LogFlowFuncEnter();
443
444 EventMap::const_iterator itEvent = m_mapEvents.begin();
445 while (itEvent != m_mapEvents.end())
446 {
447 delete itEvent->second;
448 m_mapEvents.erase(itEvent);
449
450 itEvent = m_mapEvents.begin();
451 }
452
453 LogFlowFuncLeaveRC(rc);
454 return rc;
455}
456
457/**
458 * Signals an event.
459 * Will return VERR_NOT_FOUND if no event has been found.
460 *
461 * @returns VBox status code.
462 * @param uMsg Message ID of event to signal.
463 */
464int SharedClipboardProvider::eventSignal(uint32_t uMsg)
465{
466 LogFlowFunc(("uMsg=%RU32\n", uMsg));
467
468 int rc;
469
470 EventMap::const_iterator itEvent = m_mapEvents.find(uMsg);
471 if (itEvent != m_mapEvents.end())
472 {
473 rc = RTSemEventSignal(itEvent->second->mEvent);
474 }
475 else
476 rc = VERR_NOT_FOUND;
477
478 LogFlowFuncLeaveRC(rc);
479 return rc;
480}
481
482/**
483 * Returns the event for a specific message ID.
484 *
485 * @returns Pointer to event if found, or NULL if no event has been found
486 * @param uMsg Messagae ID to return event for.
487 */
488SharedClipboardProvider::Event *SharedClipboardProvider::eventGet(uint32_t uMsg)
489{
490 LogFlowFuncEnter();
491
492 EventMap::const_iterator itEvent = m_mapEvents.find(uMsg);
493 if (itEvent != m_mapEvents.end())
494 return itEvent->second;
495
496 return NULL;
497}
498
499/**
500 * Waits for an event to get signalled and optionally returns related event data on success.
501 *
502 * @returns VBox status code.
503 * @param uMsg Message ID of event to wait for.
504 * @param pfnCallback Callback to use before waiting for event. Specify NULL if not needed.
505 * @param uTimeoutMs Timeout (in ms) to wait for.
506 * @param ppvData Where to store the related event data. Optioanl.
507 * @param pcbData Where to store the size (in bytes) of the related event data. Optioanl.
508 */
509int SharedClipboardProvider::eventWait(uint32_t uMsg, PFNSSHAREDCLIPBOARDPROVIDERCALLBACK pfnCallback,
510 RTMSINTERVAL uTimeoutMs, void **ppvData, uint32_t *pcbData /* = NULL */)
511{
512 LogFlowFunc(("uMsg=%RU32, uTimeoutMs=%RU32\n", uMsg, uTimeoutMs));
513
514 int rc = VINF_SUCCESS;
515
516 if (pfnCallback)
517 {
518 SHAREDCLIPBOARDPROVIDERCALLBACKDATA data = { this, m_Callbacks.pvUser };
519 rc = pfnCallback(&data);
520 }
521
522 if (RT_SUCCESS(rc))
523 {
524 Event *pEvent = eventGet(uMsg);
525 if (pEvent)
526 {
527 rc = pEvent->Wait(m_uTimeoutMs);
528 if (RT_SUCCESS(rc))
529 {
530 if (pcbData)
531 *pcbData = pEvent->DataSize();
532
533 if (ppvData)
534 *ppvData = pEvent->DataAdopt();
535
536 pEvent->Reset();
537 }
538 }
539 else
540 rc = VERR_NOT_FOUND;
541 }
542
543 LogFlowFuncLeaveRC(rc);
544 return rc;
545}
546
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