VirtualBox

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

Last change on this file since 58312 was 58232, checked in by vboxsync, 9 years ago

DnD: More validation.

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