VirtualBox

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

Last change on this file since 83489 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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