VirtualBox

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

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

DnD/Main: Added validation mask for the DND_OBJCTX_STATE_ flags, docs.

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