VirtualBox

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

Last change on this file since 62485 was 62485, checked in by vboxsync, 8 years ago

(C) 2016

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