VirtualBox

source: vbox/trunk/src/VBox/Main/include/GuestDnDPrivate.h@ 72436

Last change on this file since 72436 was 71398, checked in by vboxsync, 7 years ago

DnD/Main: Got rid of defining LOG_GROUP in GuestDnDPrivate.h -- breaks logging for a lot of Guest Control stuff.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.0 KB
Line 
1/* $Id: GuestDnDPrivate.h 71398 2018-03-20 12:54:33Z vboxsync $ */
2/** @file
3 * Private guest drag and drop code, used by GuestDnDTarget +
4 * GuestDnDSource.
5 */
6
7/*
8 * Copyright (C) 2011-2017 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#ifndef ____H_GUESTDNDPRIVATE
20#define ____H_GUESTDNDPRIVATE
21
22#include <iprt/dir.h>
23#include <iprt/file.h>
24#include <iprt/path.h>
25
26#include <VBox/hgcmsvc.h> /* For PVBOXHGCMSVCPARM. */
27#include <VBox/GuestHost/DragAndDrop.h>
28#include <VBox/HostServices/DragAndDropSvc.h>
29
30/**
31 * Forward prototype declarations.
32 */
33class Guest;
34class GuestDnDBase;
35class GuestDnDResponse;
36class GuestDnDSource;
37class GuestDnDTarget;
38class Progress;
39
40/**
41 * Type definitions.
42 */
43
44/** List (vector) of MIME types. */
45typedef std::vector<com::Utf8Str> GuestDnDMIMEList;
46
47/*
48 ** @todo Put most of the implementations below in GuestDnDPrivate.cpp!
49 */
50
51class GuestDnDCallbackEvent
52{
53public:
54
55 GuestDnDCallbackEvent(void)
56 : mSemEvent(NIL_RTSEMEVENT)
57 , mRc(VINF_SUCCESS) { }
58
59 virtual ~GuestDnDCallbackEvent(void);
60
61public:
62
63 int Reset(void);
64
65 int Notify(int rc = VINF_SUCCESS);
66
67 int Result(void) const { return mRc; }
68
69 int Wait(RTMSINTERVAL msTimeout);
70
71protected:
72
73 /** Event semaphore to notify on error/completion. */
74 RTSEMEVENT mSemEvent;
75 /** Callback result. */
76 int mRc;
77};
78
79/**
80 * Class for handling the (raw) meta data.
81 */
82class GuestDnDMetaData
83{
84public:
85
86 GuestDnDMetaData(void)
87 : pvData(NULL)
88 , cbData(0)
89 , cbDataUsed(0) { }
90
91 virtual ~GuestDnDMetaData(void)
92 {
93 reset();
94 }
95
96public:
97
98 uint32_t add(const void *pvDataAdd, uint32_t cbDataAdd)
99 {
100 LogFlowThisFunc(("pvDataAdd=%p, cbDataAdd=%zu\n", pvDataAdd, cbDataAdd));
101
102 if (!cbDataAdd)
103 return 0;
104 AssertPtrReturn(pvDataAdd, 0);
105
106 int rc = resize(cbData + cbDataAdd);
107 if (RT_FAILURE(rc))
108 return 0;
109
110 Assert(cbData >= cbDataUsed + cbDataAdd);
111 memcpy((uint8_t *)pvData + cbDataUsed, pvDataAdd, cbDataAdd);
112
113 cbDataUsed += cbDataAdd;
114
115 return cbDataAdd;
116 }
117
118 uint32_t add(const std::vector<BYTE> &vecAdd)
119 {
120 if (!vecAdd.size())
121 return 0;
122
123 if (vecAdd.size() > UINT32_MAX) /* Paranoia. */
124 return 0;
125
126 return add(&vecAdd.front(), (uint32_t)vecAdd.size());
127 }
128
129 void reset(void)
130 {
131 if (pvData)
132 {
133 Assert(cbData);
134 RTMemFree(pvData);
135 pvData = NULL;
136 }
137
138 cbData = 0;
139 cbDataUsed = 0;
140 }
141
142 const void *getData(void) const { return pvData; }
143
144 void *getDataMutable(void) { return pvData; }
145
146 uint32_t getSize(void) const { return cbDataUsed; }
147
148public:
149
150 int fromString(const RTCString &strData)
151 {
152 int rc = VINF_SUCCESS;
153
154 if (strData.isNotEmpty())
155 {
156 const uint32_t cbStrData = (uint32_t)strData.length() + 1; /* Include terminating zero. */
157 rc = resize(cbStrData);
158 if (RT_SUCCESS(rc))
159 memcpy(pvData, strData.c_str(), cbStrData);
160 }
161
162 return rc;
163 }
164
165 int fromURIList(const DnDURIList &lstURI)
166 {
167 return fromString(lstURI.RootToString());
168 }
169
170protected:
171
172 int resize(uint32_t cbSize)
173 {
174 if (!cbSize)
175 {
176 reset();
177 return VINF_SUCCESS;
178 }
179
180 if (cbSize == cbData)
181 return VINF_SUCCESS;
182
183 void *pvTmp = NULL;
184 if (!cbData)
185 {
186 Assert(cbDataUsed == 0);
187 pvTmp = RTMemAllocZ(cbSize);
188 }
189 else
190 {
191 AssertPtr(pvData);
192 pvTmp = RTMemRealloc(pvData, cbSize);
193 RT_BZERO(pvTmp, cbSize);
194 }
195
196 if (pvTmp)
197 {
198 pvData = pvTmp;
199 cbData = cbSize;
200 return VINF_SUCCESS;
201 }
202
203 return VERR_NO_MEMORY;
204 }
205
206protected:
207
208 void *pvData;
209 uint32_t cbData;
210 uint32_t cbDataUsed;
211};
212
213/**
214 * Class for keeping drag and drop (meta) data
215 * to be sent/received.
216 */
217class GuestDnDData
218{
219public:
220
221 GuestDnDData(void)
222 : cbEstTotal(0)
223 , cbEstMeta(0)
224 , cbProcessed(0)
225 {
226 RT_ZERO(dataHdr);
227 }
228
229 virtual ~GuestDnDData(void)
230 {
231 reset();
232 }
233
234public:
235
236 uint64_t addProcessed(uint32_t cbDataAdd)
237 {
238 const uint64_t cbTotal = getTotal(); NOREF(cbTotal);
239 Assert(cbProcessed + cbDataAdd <= cbTotal);
240 cbProcessed += cbDataAdd;
241 return cbProcessed;
242 }
243
244 bool isComplete(void) const
245 {
246 const uint64_t cbTotal = getTotal();
247 LogFlowFunc(("cbProcessed=%RU64, cbTotal=%RU64\n", cbProcessed, cbTotal));
248 Assert(cbProcessed <= cbTotal);
249 return (cbProcessed == cbTotal);
250 }
251
252 void *getChkSumMutable(void) { return dataHdr.pvChecksum; }
253
254 uint32_t getChkSumSize(void) const { return dataHdr.cbChecksum; }
255
256 void *getFmtMutable(void) { return dataHdr.pvMetaFmt; }
257
258 uint32_t getFmtSize(void) const { return dataHdr.cbMetaFmt; }
259
260 GuestDnDMetaData &getMeta(void) { return dataMeta; }
261
262 uint8_t getPercentComplete(void) const
263 {
264 int64_t cbTotal = RT_MAX(getTotal(), 1);
265 return (uint8_t)(cbProcessed * 100 / cbTotal);
266 }
267
268 uint64_t getProcessed(void) const { return cbProcessed; }
269
270 uint64_t getRemaining(void) const
271 {
272 const uint64_t cbTotal = getTotal();
273 Assert(cbProcessed <= cbTotal);
274 return cbTotal - cbProcessed;
275 }
276
277 uint64_t getTotal(void) const { return cbEstTotal; }
278
279 void reset(void)
280 {
281 clearFmt();
282 clearChkSum();
283
284 RT_ZERO(dataHdr);
285
286 dataMeta.reset();
287
288 cbEstTotal = 0;
289 cbEstMeta = 0;
290 cbProcessed = 0;
291 }
292
293 int setFmt(const void *pvFmt, uint32_t cbFmt)
294 {
295 if (cbFmt)
296 {
297 AssertPtrReturn(pvFmt, VERR_INVALID_POINTER);
298 void *pvFmtTmp = RTMemAlloc(cbFmt);
299 if (!pvFmtTmp)
300 return VERR_NO_MEMORY;
301
302 clearFmt();
303
304 memcpy(pvFmtTmp, pvFmt, cbFmt);
305
306 dataHdr.pvMetaFmt = pvFmtTmp;
307 dataHdr.cbMetaFmt = cbFmt;
308 }
309 else
310 clearFmt();
311
312 return VINF_SUCCESS;
313 }
314
315 void setEstimatedSize(uint64_t cbTotal, uint32_t cbMeta)
316 {
317 Assert(cbMeta <= cbTotal);
318
319 LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32\n", cbTotal, cbMeta));
320
321 cbEstTotal = cbTotal;
322 cbEstMeta = cbMeta;
323 }
324
325protected:
326
327 void clearChkSum(void)
328 {
329 if (dataHdr.pvChecksum)
330 {
331 Assert(dataHdr.cbChecksum);
332 RTMemFree(dataHdr.pvChecksum);
333 dataHdr.pvChecksum = NULL;
334 }
335
336 dataHdr.cbChecksum = 0;
337 }
338
339 void clearFmt(void)
340 {
341 if (dataHdr.pvMetaFmt)
342 {
343 Assert(dataHdr.cbMetaFmt);
344 RTMemFree(dataHdr.pvMetaFmt);
345 dataHdr.pvMetaFmt = NULL;
346 }
347
348 dataHdr.cbMetaFmt = 0;
349 }
350
351protected:
352
353 /** The data header. */
354 VBOXDNDDATAHDR dataHdr;
355 /** For storing the actual meta data.
356 * This might be an URI list or just plain raw data,
357 * according to the format being sent. */
358 GuestDnDMetaData dataMeta;
359 /** Estimated total data size when receiving data. */
360 uint64_t cbEstTotal;
361 /** Estimated meta data size when receiving data. */
362 uint32_t cbEstMeta;
363 /** Overall size (in bytes) of processed data. */
364 uint64_t cbProcessed;
365};
366
367/** Initial state. */
368#define DND_OBJCTX_STATE_NONE 0
369/** The header was received/sent. */
370#define DND_OBJCTX_STATE_HAS_HDR RT_BIT(0)
371
372/**
373 * Structure for keeping a DnDURIObject context around.
374 */
375class GuestDnDURIObjCtx
376{
377public:
378
379 GuestDnDURIObjCtx(void)
380 : pObjURI(NULL)
381 , fIntermediate(false)
382 , fState(DND_OBJCTX_STATE_NONE) { }
383
384 virtual ~GuestDnDURIObjCtx(void)
385 {
386 destroy();
387 }
388
389public:
390
391 int createIntermediate(DnDURIObject::Type enmType = DnDURIObject::Unknown)
392 {
393 reset();
394
395 int rc;
396
397 try
398 {
399 pObjURI = new DnDURIObject(enmType);
400 fIntermediate = true;
401
402 rc = VINF_SUCCESS;
403 }
404 catch (std::bad_alloc &)
405 {
406 rc = VERR_NO_MEMORY;
407 }
408
409 LogThisFunc(("Returning %Rrc\n", rc));
410 return rc;
411 }
412
413 void destroy(void)
414 {
415 LogFlowThisFuncEnter();
416
417 if ( pObjURI
418 && fIntermediate)
419 {
420 delete pObjURI;
421 }
422
423 pObjURI = NULL;
424 fIntermediate = false;
425 }
426
427 DnDURIObject *getObj(void) const { return pObjURI; }
428
429 bool isIntermediate(void) { return fIntermediate; }
430
431 bool isValid(void) const { return (pObjURI != NULL); }
432
433 uint32_t getState(void) const { return fState; }
434
435 void reset(void)
436 {
437 LogFlowThisFuncEnter();
438
439 destroy();
440
441 fIntermediate = false;
442 fState = 0;
443 }
444
445 void setObj(DnDURIObject *pObj)
446 {
447 LogFlowThisFunc(("%p\n", pObj));
448
449 destroy();
450
451 pObjURI = pObj;
452 }
453
454 uint32_t setState(uint32_t fStateNew)
455 {
456 /** @todo Add validation. */
457 fState = fStateNew;
458 return fState;
459 }
460
461protected:
462
463 /** Pointer to current object being handled. */
464 DnDURIObject *pObjURI;
465 /** Flag whether pObjURI needs deletion after use. */
466 bool fIntermediate;
467 /** Internal context state, corresponding to DND_OBJCTX_STATE_XXX. */
468 uint32_t fState;
469 /** @todo Add more statistics / information here. */
470};
471
472/**
473 * Structure for keeping around an URI (data) transfer.
474 */
475class GuestDnDURIData
476{
477
478public:
479
480 GuestDnDURIData(void)
481 : cObjToProcess(0)
482 , cObjProcessed(0)
483 , pvScratchBuf(NULL)
484 , cbScratchBuf(0) { }
485
486 virtual ~GuestDnDURIData(void)
487 {
488 reset();
489
490 if (pvScratchBuf)
491 {
492 Assert(cbScratchBuf);
493 RTMemFree(pvScratchBuf);
494 pvScratchBuf = NULL;
495 }
496 cbScratchBuf = 0;
497 }
498
499 DnDDroppedFiles &getDroppedFiles(void) { return droppedFiles; }
500
501 DnDURIList &getURIList(void) { return lstURI; }
502
503 int init(size_t cbBuf = _64K)
504 {
505 reset();
506
507 pvScratchBuf = RTMemAlloc(cbBuf);
508 if (!pvScratchBuf)
509 return VERR_NO_MEMORY;
510
511 cbScratchBuf = cbBuf;
512 return VINF_SUCCESS;
513 }
514
515 bool isComplete(void) const
516 {
517 LogFlowFunc(("cObjProcessed=%RU64, cObjToProcess=%RU64\n", cObjProcessed, cObjToProcess));
518
519 if (!cObjToProcess) /* Always return true if we don't have an object count. */
520 return true;
521
522 Assert(cObjProcessed <= cObjToProcess);
523 return (cObjProcessed == cObjToProcess);
524 }
525
526 const void *getBuffer(void) const { return pvScratchBuf; }
527
528 void *getBufferMutable(void) { return pvScratchBuf; }
529
530 size_t getBufferSize(void) const { return cbScratchBuf; }
531
532 GuestDnDURIObjCtx &getObj(uint64_t uID = 0)
533 {
534 RT_NOREF(uID);
535 AssertMsg(uID == 0, ("Other objects than object 0 is not supported yet\n"));
536 return objCtx;
537 }
538
539 GuestDnDURIObjCtx &getObjCurrent(void)
540 {
541 DnDURIObject *pCurObj = lstURI.First();
542 if ( !lstURI.IsEmpty()
543 && pCurObj)
544 {
545 /* Point the context object to the current DnDURIObject to process. */
546 objCtx.setObj(pCurObj);
547 }
548 else
549 objCtx.reset();
550
551 return objCtx;
552 }
553
554 uint64_t getObjToProcess(void) const { return cObjToProcess; }
555
556 uint64_t getObjProcessed(void) const { return cObjProcessed; }
557
558 int processObject(const DnDURIObject &Obj)
559 {
560 int rc;
561
562 /** @todo Find objct in lstURI first! */
563 switch (Obj.GetType())
564 {
565 case DnDURIObject::Directory:
566 case DnDURIObject::File:
567 rc = VINF_SUCCESS;
568 break;
569
570 default:
571 rc = VERR_NOT_IMPLEMENTED;
572 break;
573 }
574
575 if (RT_SUCCESS(rc))
576 {
577 if (cObjToProcess)
578 {
579 cObjProcessed++;
580 Assert(cObjProcessed <= cObjToProcess);
581 }
582 }
583
584 return rc;
585 }
586
587 void removeObjCurrent(void)
588 {
589 if (cObjToProcess)
590 {
591 cObjProcessed++;
592 Assert(cObjProcessed <= cObjToProcess);
593 }
594
595 lstURI.RemoveFirst();
596 objCtx.reset();
597 }
598
599 void reset(void)
600 {
601 LogFlowFuncEnter();
602
603 cObjToProcess = 0;
604 cObjProcessed = 0;
605
606 droppedFiles.Close();
607
608 lstURI.Clear();
609 objCtx.reset();
610 }
611
612 void setEstimatedObjects(uint64_t cObjs)
613 {
614 Assert(cObjToProcess == 0);
615 cObjToProcess = cObjs;
616 LogFlowFunc(("cObjToProcess=%RU64\n", cObjs));
617 }
618
619public:
620
621 int fromLocalMetaData(const GuestDnDMetaData &Data)
622 {
623 reset();
624
625 if (!Data.getSize())
626 return VINF_SUCCESS;
627
628 char *pszList;
629 int rc = RTStrCurrentCPToUtf8(&pszList, (const char *)Data.getData());
630 if (RT_FAILURE(rc))
631 {
632 LogFlowThisFunc(("String conversion failed with rc=%Rrc\n", rc));
633 return rc;
634 }
635
636 const size_t cbList = Data.getSize();
637 LogFlowThisFunc(("metaData=%p, cbList=%zu\n", &Data, cbList));
638
639 if (cbList)
640 {
641 RTCList<RTCString> lstURIOrg = RTCString(pszList, cbList).split("\r\n");
642 if (!lstURIOrg.isEmpty())
643 {
644 /* Note: All files to be transferred will be kept open during the entire DnD
645 * operation, also to keep the accounting right. */
646 rc = lstURI.AppendURIPathsFromList(lstURIOrg, DNDURILIST_FLAGS_KEEP_OPEN);
647 if (RT_SUCCESS(rc))
648 cObjToProcess = lstURI.TotalCount();
649 }
650 }
651
652 RTStrFree(pszList);
653 return rc;
654 }
655
656 int fromRemoteMetaData(const GuestDnDMetaData &Data)
657 {
658 LogFlowFuncEnter();
659
660 int rc = lstURI.RootFromURIData(Data.getData(), Data.getSize(), 0 /* uFlags */);
661 if (RT_SUCCESS(rc))
662 {
663 const size_t cRootCount = lstURI.RootCount();
664 LogFlowFunc(("cRootCount=%zu, cObjToProcess=%RU64\n", cRootCount, cObjToProcess));
665 if (cRootCount > cObjToProcess)
666 rc = VERR_INVALID_PARAMETER;
667 }
668
669 return rc;
670 }
671
672 int toMetaData(std::vector<BYTE> &vecData)
673 {
674 const char *pszDroppedFilesDir = droppedFiles.GetDirAbs();
675
676 Utf8Str strURIs = lstURI.RootToString(RTCString(pszDroppedFilesDir));
677 size_t cbData = strURIs.length();
678
679 LogFlowFunc(("%zu root URIs (%zu bytes)\n", lstURI.RootCount(), cbData));
680
681 int rc;
682
683 try
684 {
685 vecData.resize(cbData + 1 /* Include termination */);
686 memcpy(&vecData.front(), strURIs.c_str(), cbData);
687
688 rc = VINF_SUCCESS;
689 }
690 catch (std::bad_alloc &)
691 {
692 rc = VERR_NO_MEMORY;
693 }
694
695 return rc;
696 }
697
698protected:
699
700 int processDirectory(const char *pszPath, uint32_t fMode)
701 {
702 /** @todo Find directory in lstURI first! */
703 int rc;
704
705 const char *pszDroppedFilesDir = droppedFiles.GetDirAbs();
706 char *pszDir = RTPathJoinA(pszDroppedFilesDir, pszPath);
707 if (pszDir)
708 {
709 rc = RTDirCreateFullPath(pszDir, fMode);
710 if (cObjToProcess)
711 {
712 cObjProcessed++;
713 Assert(cObjProcessed <= cObjToProcess);
714 }
715
716 RTStrFree(pszDir);
717 }
718 else
719 rc = VERR_NO_MEMORY;
720
721 return rc;
722 }
723
724protected:
725
726 /** Number of objects to process. */
727 uint64_t cObjToProcess;
728 /** Number of objects already processed. */
729 uint64_t cObjProcessed;
730 /** Handles all drop files for this operation. */
731 DnDDroppedFiles droppedFiles;
732 /** (Non-recursive) List of URI objects to handle. */
733 DnDURIList lstURI;
734 /** Context to current object being handled.
735 * As we currently do all transfers one after another we
736 * only have one context at a time. */
737 GuestDnDURIObjCtx objCtx;
738 /** Pointer to an optional scratch buffer to use for
739 * doing the actual chunk transfers. */
740 void *pvScratchBuf;
741 /** Size (in bytes) of scratch buffer. */
742 size_t cbScratchBuf;
743};
744
745/**
746 * Context structure for sending data to the guest.
747 */
748typedef struct SENDDATACTX
749{
750 /** Pointer to guest target class this context belongs to. */
751 GuestDnDTarget *mpTarget;
752 /** Pointer to guest response class this context belongs to. */
753 GuestDnDResponse *mpResp;
754 /** Flag indicating whether a file transfer is active and
755 * initiated by the host. */
756 bool mIsActive;
757 /** Target (VM) screen ID. */
758 uint32_t mScreenID;
759 /** Drag'n drop format requested by the guest. */
760 com::Utf8Str mFmtReq;
761 /** Drag'n drop data to send.
762 * This can be arbitrary data or an URI list. */
763 GuestDnDData mData;
764 /** URI data structure. */
765 GuestDnDURIData mURI;
766 /** Callback event to use. */
767 GuestDnDCallbackEvent mCBEvent;
768
769} SENDDATACTX, *PSENDDATACTX;
770
771/**
772 * Context structure for receiving data from the guest.
773 */
774typedef struct RECVDATACTX
775{
776 /** Pointer to guest source class this context belongs to. */
777 GuestDnDSource *mpSource;
778 /** Pointer to guest response class this context belongs to. */
779 GuestDnDResponse *mpResp;
780 /** Flag indicating whether a file transfer is active and
781 * initiated by the host. */
782 bool mIsActive;
783 /** Formats offered by the guest (and supported by the host). */
784 GuestDnDMIMEList mFmtOffered;
785 /** Original drop format requested to receive from the guest. */
786 com::Utf8Str mFmtReq;
787 /** Intermediate drop format to be received from the guest.
788 * Some original drop formats require a different intermediate
789 * drop format:
790 *
791 * Receiving a file link as "text/plain" requires still to
792 * receive the file from the guest as "text/uri-list" first,
793 * then pointing to the file path on the host with the data
794 * in "text/plain" format returned. */
795 com::Utf8Str mFmtRecv;
796 /** Desired drop action to perform on the host.
797 * Needed to tell the guest if data has to be
798 * deleted e.g. when moving instead of copying. */
799 uint32_t mAction;
800 /** Drag'n drop received from the guest.
801 * This can be arbitrary data or an URI list. */
802 GuestDnDData mData;
803 /** URI data structure. */
804 GuestDnDURIData mURI;
805 /** Callback event to use. */
806 GuestDnDCallbackEvent mCBEvent;
807
808} RECVDATACTX, *PRECVDATACTX;
809
810/**
811 * Simple structure for a buffered guest DnD message.
812 */
813class GuestDnDMsg
814{
815public:
816
817 GuestDnDMsg(void)
818 : uMsg(0)
819 , cParms(0)
820 , cParmsAlloc(0)
821 , paParms(NULL) { }
822
823 virtual ~GuestDnDMsg(void)
824 {
825 reset();
826 }
827
828public:
829
830 PVBOXHGCMSVCPARM getNextParam(void)
831 {
832 if (cParms >= cParmsAlloc)
833 {
834 if (!paParms)
835 paParms = (PVBOXHGCMSVCPARM)RTMemAlloc(4 * sizeof(VBOXHGCMSVCPARM));
836 else
837 paParms = (PVBOXHGCMSVCPARM)RTMemRealloc(paParms, (cParmsAlloc + 4) * sizeof(VBOXHGCMSVCPARM));
838 if (!paParms)
839 throw VERR_NO_MEMORY;
840 RT_BZERO(&paParms[cParmsAlloc], 4 * sizeof(VBOXHGCMSVCPARM));
841 cParmsAlloc += 4;
842 }
843
844 return &paParms[cParms++];
845 }
846
847 uint32_t getCount(void) const { return cParms; }
848 PVBOXHGCMSVCPARM getParms(void) const { return paParms; }
849 uint32_t getType(void) const { return uMsg; }
850
851 void reset(void)
852 {
853 if (paParms)
854 {
855 /* Remove deep copies. */
856 for (uint32_t i = 0; i < cParms; i++)
857 {
858 if ( paParms[i].type == VBOX_HGCM_SVC_PARM_PTR
859 && paParms[i].u.pointer.size)
860 {
861 AssertPtr(paParms[i].u.pointer.addr);
862 RTMemFree(paParms[i].u.pointer.addr);
863 }
864 }
865
866 RTMemFree(paParms);
867 paParms = NULL;
868 }
869
870 uMsg = cParms = cParmsAlloc = 0;
871 }
872
873 int setNextPointer(void *pvBuf, uint32_t cbBuf)
874 {
875 PVBOXHGCMSVCPARM pParm = getNextParam();
876 if (!pParm)
877 return VERR_NO_MEMORY;
878
879 void *pvTmp = NULL;
880 if (pvBuf)
881 {
882 Assert(cbBuf);
883 pvTmp = RTMemDup(pvBuf, cbBuf);
884 if (!pvTmp)
885 return VERR_NO_MEMORY;
886 }
887
888 pParm->setPointer(pvTmp, cbBuf);
889 return VINF_SUCCESS;
890 }
891
892 int setNextString(const char *pszString)
893 {
894 PVBOXHGCMSVCPARM pParm = getNextParam();
895 if (!pParm)
896 return VERR_NO_MEMORY;
897
898 char *pszTemp = RTStrDup(pszString);
899 if (!pszTemp)
900 return VERR_NO_MEMORY;
901
902 pParm->setString(pszTemp);
903 return VINF_SUCCESS;
904 }
905
906 int setNextUInt32(uint32_t u32Val)
907 {
908 PVBOXHGCMSVCPARM pParm = getNextParam();
909 if (!pParm)
910 return VERR_NO_MEMORY;
911
912 pParm->setUInt32(u32Val);
913 return VINF_SUCCESS;
914 }
915
916 int setNextUInt64(uint64_t u64Val)
917 {
918 PVBOXHGCMSVCPARM pParm = getNextParam();
919 if (!pParm)
920 return VERR_NO_MEMORY;
921
922 pParm->setUInt64(u64Val);
923 return VINF_SUCCESS;
924 }
925
926 void setType(uint32_t uMsgType) { uMsg = uMsgType; }
927
928protected:
929
930 /** Message type. */
931 uint32_t uMsg;
932 /** Message parameters. */
933 uint32_t cParms;
934 /** Size of array. */
935 uint32_t cParmsAlloc;
936 /** Array of HGCM parameters */
937 PVBOXHGCMSVCPARM paParms;
938};
939
940/** Guest DnD callback function definition. */
941typedef DECLCALLBACKPTR(int, PFNGUESTDNDCALLBACK) (uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser);
942
943/**
944 * Structure for keeping a guest DnD callback.
945 * Each callback can handle one HGCM message, however, multiple HGCM messages can be registered
946 * to the same callback (function).
947 */
948typedef struct GuestDnDCallback
949{
950 GuestDnDCallback(void)
951 : uMessgage(0)
952 , pfnCallback(NULL)
953 , pvUser(NULL) { }
954
955 GuestDnDCallback(PFNGUESTDNDCALLBACK pvCB, uint32_t uMsg, void *pvUsr = NULL)
956 : uMessgage(uMsg)
957 , pfnCallback(pvCB)
958 , pvUser(pvUsr) { }
959
960 /** The HGCM message ID to handle. */
961 uint32_t uMessgage;
962 /** Pointer to callback function. */
963 PFNGUESTDNDCALLBACK pfnCallback;
964 /** Pointer to user-supplied data. */
965 void *pvUser;
966
967} GuestDnDCallback;
968
969/** Contains registered callback pointers for specific HGCM message types. */
970typedef std::map<uint32_t, GuestDnDCallback> GuestDnDCallbackMap;
971
972/** @todo r=andy This class needs to go, as this now is too inflexible when it comes to all
973 * the callback handling/dispatching. It's part of the initial code and only adds
974 * unnecessary complexity. */
975class GuestDnDResponse
976{
977
978public:
979
980 GuestDnDResponse(const ComObjPtr<Guest>& pGuest);
981 virtual ~GuestDnDResponse(void);
982
983public:
984
985 int notifyAboutGuestResponse(void) const;
986 int waitForGuestResponse(RTMSINTERVAL msTimeout = 500) const;
987
988 void setAllActions(uint32_t a) { m_allActions = a; }
989 uint32_t allActions(void) const { return m_allActions; }
990
991 void setDefAction(uint32_t a) { m_defAction = a; }
992 uint32_t defAction(void) const { return m_defAction; }
993
994 void setFormats(const GuestDnDMIMEList &lstFormats) { m_lstFormats = lstFormats; }
995 GuestDnDMIMEList formats(void) const { return m_lstFormats; }
996
997 void reset(void);
998
999 bool isProgressCanceled(void) const;
1000 int setCallback(uint32_t uMsg, PFNGUESTDNDCALLBACK pfnCallback, void *pvUser = NULL);
1001 int setProgress(unsigned uPercentage, uint32_t uState, int rcOp = VINF_SUCCESS, const Utf8Str &strMsg = "");
1002 HRESULT resetProgress(const ComObjPtr<Guest>& pParent);
1003 HRESULT queryProgressTo(IProgress **ppProgress);
1004
1005public:
1006
1007 /** @name HGCM callback handling.
1008 @{ */
1009 int onDispatch(uint32_t u32Function, void *pvParms, uint32_t cbParms);
1010 /** @} */
1011
1012protected:
1013
1014 /** Pointer to context this class is tied to. */
1015 void *m_pvCtx;
1016 /** Event for waiting for response. */
1017 RTSEMEVENT m_EventSem;
1018 /** Default action to perform in case of a
1019 * successful drop. */
1020 uint32_t m_defAction;
1021 /** Actions supported by the guest in case of
1022 * a successful drop. */
1023 uint32_t m_allActions;
1024 /** Format(s) requested/supported from the guest. */
1025 GuestDnDMIMEList m_lstFormats;
1026 /** Pointer to IGuest parent object. */
1027 ComObjPtr<Guest> m_pParent;
1028 /** Pointer to associated progress object. Optional. */
1029 ComObjPtr<Progress> m_pProgress;
1030 /** Callback map. */
1031 GuestDnDCallbackMap m_mapCallbacks;
1032};
1033
1034/**
1035 * Private singleton class for the guest's DnD
1036 * implementation. Can't be instanciated directly, only via
1037 * the factory pattern.
1038 *
1039 ** @todo Move this into GuestDnDBase.
1040 */
1041class GuestDnD
1042{
1043public:
1044
1045 static GuestDnD *createInstance(const ComObjPtr<Guest>& pGuest)
1046 {
1047 Assert(NULL == GuestDnD::s_pInstance);
1048 GuestDnD::s_pInstance = new GuestDnD(pGuest);
1049 return GuestDnD::s_pInstance;
1050 }
1051
1052 static void destroyInstance(void)
1053 {
1054 if (GuestDnD::s_pInstance)
1055 {
1056 delete GuestDnD::s_pInstance;
1057 GuestDnD::s_pInstance = NULL;
1058 }
1059 }
1060
1061 static inline GuestDnD *getInstance(void)
1062 {
1063 AssertPtr(GuestDnD::s_pInstance);
1064 return GuestDnD::s_pInstance;
1065 }
1066
1067protected:
1068
1069 GuestDnD(const ComObjPtr<Guest>& pGuest);
1070 virtual ~GuestDnD(void);
1071
1072public:
1073
1074 /** @name Public helper functions.
1075 * @{ */
1076 HRESULT adjustScreenCoordinates(ULONG uScreenId, ULONG *puX, ULONG *puY) const;
1077 int hostCall(uint32_t u32Function, uint32_t cParms, PVBOXHGCMSVCPARM paParms) const;
1078 GuestDnDResponse *response(void) { return m_pResponse; }
1079 GuestDnDMIMEList defaultFormats(void) const { return m_strDefaultFormats; }
1080 /** @} */
1081
1082public:
1083
1084 /** @name Static low-level HGCM callback handler.
1085 * @{ */
1086 static DECLCALLBACK(int) notifyDnDDispatcher(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms);
1087 /** @} */
1088
1089 /** @name Static helper methods.
1090 * @{ */
1091 static bool isFormatInFormatList(const com::Utf8Str &strFormat, const GuestDnDMIMEList &lstFormats);
1092 static GuestDnDMIMEList toFormatList(const com::Utf8Str &strFormats);
1093 static com::Utf8Str toFormatString(const GuestDnDMIMEList &lstFormats);
1094 static GuestDnDMIMEList toFilteredFormatList(const GuestDnDMIMEList &lstFormatsSupported, const GuestDnDMIMEList &lstFormatsWanted);
1095 static GuestDnDMIMEList toFilteredFormatList(const GuestDnDMIMEList &lstFormatsSupported, const com::Utf8Str &strFormatsWanted);
1096 static DnDAction_T toMainAction(uint32_t uAction);
1097 static std::vector<DnDAction_T> toMainActions(uint32_t uActions);
1098 static uint32_t toHGCMAction(DnDAction_T enmAction);
1099 static void toHGCMActions(DnDAction_T enmDefAction, uint32_t *puDefAction, const std::vector<DnDAction_T> vecAllowedActions, uint32_t *puAllowedActions);
1100 /** @} */
1101
1102protected:
1103
1104 /** @name Singleton properties.
1105 * @{ */
1106 /** List of supported default MIME/Content-type formats. */
1107 GuestDnDMIMEList m_strDefaultFormats;
1108 /** Pointer to guest implementation. */
1109 const ComObjPtr<Guest> m_pGuest;
1110 /** The current (last) response from the guest. At the
1111 * moment we only support only response a time (ARQ-style). */
1112 GuestDnDResponse *m_pResponse;
1113 /** @} */
1114
1115private:
1116
1117 /** Staic pointer to singleton instance. */
1118 static GuestDnD *s_pInstance;
1119};
1120
1121/** Access to the GuestDnD's singleton instance.
1122 * @todo r=bird: Please add a 'Get' or something to this as it currently looks
1123 * like a class instantiation rather than a getter. Alternatively, use
1124 * UPPER_CASE like the coding guideline suggest for macros. */
1125#define GuestDnDInst() GuestDnD::getInstance()
1126
1127/** List of pointers to guest DnD Messages. */
1128typedef std::list<GuestDnDMsg *> GuestDnDMsgList;
1129
1130/**
1131 * IDnDBase class implementation for sharing code between
1132 * IGuestDnDSource and IGuestDnDTarget implementation.
1133 */
1134class GuestDnDBase
1135{
1136protected:
1137
1138 GuestDnDBase(void);
1139
1140protected:
1141
1142 /** Shared (internal) IDnDBase method implementations.
1143 * @{ */
1144 HRESULT i_isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported);
1145 HRESULT i_getFormats(GuestDnDMIMEList &aFormats);
1146 HRESULT i_addFormats(const GuestDnDMIMEList &aFormats);
1147 HRESULT i_removeFormats(const GuestDnDMIMEList &aFormats);
1148
1149 HRESULT i_getProtocolVersion(ULONG *puVersion);
1150 /** @} */
1151
1152protected:
1153
1154 int getProtocolVersion(uint32_t *puVersion);
1155
1156 /** @name Functions for handling a simple host HGCM message queue.
1157 * @{ */
1158 int msgQueueAdd(GuestDnDMsg *pMsg);
1159 GuestDnDMsg *msgQueueGetNext(void);
1160 void msgQueueRemoveNext(void);
1161 void msgQueueClear(void);
1162 /** @} */
1163
1164 int sendCancel(void);
1165 int updateProgress(GuestDnDData *pData, GuestDnDResponse *pResp, uint32_t cbDataAdd = 0);
1166 int waitForEvent(GuestDnDCallbackEvent *pEvent, GuestDnDResponse *pResp, RTMSINTERVAL msTimeout);
1167
1168protected:
1169
1170 /** @name Public attributes (through getters/setters).
1171 * @{ */
1172 /** Pointer to guest implementation. */
1173 const ComObjPtr<Guest> m_pGuest;
1174 /** List of supported MIME types by the source. */
1175 GuestDnDMIMEList m_lstFmtSupported;
1176 /** List of offered MIME types to the counterpart. */
1177 GuestDnDMIMEList m_lstFmtOffered;
1178 /** @} */
1179
1180 /**
1181 * Internal stuff.
1182 */
1183 struct
1184 {
1185 /** Number of active transfers (guest->host or host->guest). */
1186 uint32_t m_cTransfersPending;
1187 /** The DnD protocol version to use, depending on the
1188 * installed Guest Additions. See DragAndDropSvc.h for
1189 * a protocol changelog. */
1190 uint32_t m_uProtocolVersion;
1191 /** Outgoing message queue (FIFO). */
1192 GuestDnDMsgList m_lstMsgOut;
1193 } mDataBase;
1194};
1195#endif /* ____H_GUESTDNDPRIVATE */
1196
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