VirtualBox

Ignore:
Timestamp:
Feb 19, 2014 3:45:58 PM (11 years ago)
Author:
vboxsync
Message:

DnD: Update.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp

    r50462 r50508  
    3838#include <iprt/cpp/ministring.h>
    3939
     40#ifdef LOG_GROUP
     41 #undef LOG_GROUP
     42#endif
     43#define LOG_GROUP LOG_GROUP_GUEST_DND
     44#include <VBox/log.h>
     45
    4046#include <VBox/GuestHost/DragAndDrop.h>
    4147#include <VBox/HostServices/DragAndDropSvc.h>
     
    7985        if (RT_SUCCESS(rc))
    8086        {
    81             /* Fetch results */
    8287            rc = Msg.msg.GetUInt32(puMsg);         AssertRC(rc);
    8388            rc = Msg.num_parms.GetUInt32(pcParms); AssertRC(rc);
     
    128133        if (RT_SUCCESS(rc))
    129134        {
    130             /* Fetch results */
    131135            rc = Msg.uScreenId.GetUInt32(puScreenId);     AssertRC(rc);
    132136            rc = Msg.uX.GetUInt32(puX);                   AssertRC(rc);
     
    135139            rc = Msg.uAllActions.GetUInt32(puAllActions); AssertRC(rc);
    136140            rc = Msg.cFormats.GetUInt32(pcbFormatsRecv);  AssertRC(rc);
    137             /* A little bit paranoia */
     141
    138142            AssertReturn(cbFormats >= *pcbFormatsRecv, VERR_TOO_MUCH_DATA);
    139143        }
     
    191195
    192196    Msg.pvName.SetPtr(pszDirname, cbDirname);
    193     Msg.cName.SetUInt32(0);
     197    Msg.cbName.SetUInt32(0);
    194198    Msg.fMode.SetUInt32(0);
    195199
     
    200204        if (RT_SUCCESS(Msg.hdr.result))
    201205        {
    202             /* Fetch results */
    203             rc = Msg.cName.GetUInt32(pcbDirnameRecv); AssertRC(rc);
    204             rc = Msg.fMode.GetUInt32(pfMode);         AssertRC(rc);
    205             /* A little bit paranoia */
     206            rc = Msg.cbName.GetUInt32(pcbDirnameRecv); AssertRC(rc);
     207            rc = Msg.fMode.GetUInt32(pfMode);          AssertRC(rc);
     208
    206209            AssertReturn(cbDirname >= *pcbDirnameRecv, VERR_TOO_MUCH_DATA);
    207210        }
     
    235238
    236239    Msg.pvName.SetPtr(pszFilename, cbFilename);
    237     Msg.cName.SetUInt32(0);
     240    Msg.cbName.SetUInt32(0);
    238241    Msg.pvData.SetPtr(pvData, cbData);
    239     Msg.cData.SetUInt32(0);
     242    Msg.cbData.SetUInt32(0);
    240243    Msg.fMode.SetUInt32(0);
    241244
     
    246249        if (RT_SUCCESS(rc))
    247250        {
    248             /* Fetch results */
    249             rc = Msg.cName.GetUInt32(pcbFilenameRecv); AssertRC(rc);
    250             rc = Msg.cData.GetUInt32(pcbDataRecv);     AssertRC(rc);
    251             rc = Msg.fMode.GetUInt32(pfMode);          AssertRC(rc);
    252             /* A little bit paranoia */
     251            rc = Msg.cbName.GetUInt32(pcbFilenameRecv); AssertRC(rc);
     252            rc = Msg.cbData.GetUInt32(pcbDataRecv);     AssertRC(rc);
     253            rc = Msg.fMode.GetUInt32(pfMode);           AssertRC(rc);
     254
    253255            AssertReturn(cbFilename >= *pcbFilenameRecv, VERR_TOO_MUCH_DATA);
    254256            AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
     
    275277        return VERR_INVALID_PARAMETER;
    276278
    277     /* Make a string list out of the uri data. */
    278     RTCList<RTCString> uriList =
    279         RTCString(static_cast<char*>(*ppvData), *pcbDataRecv - 1).split("\r\n");
    280     if (uriList.isEmpty())
    281         return VINF_SUCCESS;
    282 
     279    /* Allocate temp buffer. */
    283280    uint32_t cbTmpData = _1M * 10; /** @todo r=andy 10MB, uh, really?? */
    284281    void *pvTmpData = RTMemAlloc(cbTmpData);
     
    297294    /* Patch the old drop data with the new drop directory, so the drop target
    298295     * can find the files. */
    299     RTCList<RTCString> guestUriList;
    300     for (size_t i = 0; i < uriList.size(); ++i)
    301     {
    302         const RTCString &strUri = uriList.at(i);
    303         /* Query the path component of a file URI. If this hasn't a
    304          * file scheme, null is returned. */
    305         char *pszFilePath = RTUriFilePath(strUri.c_str(), URI_FILE_FORMAT_AUTO);
    306         if (pszFilePath)
    307         {
    308             rc = DnDPathSanitize(pszFilePath, strlen(pszFilePath));
    309             if (RT_FAILURE(rc))
    310                 break;
    311 
    312             /** @todo Use RTPathJoin? */
    313             RTCString strFullPath
    314                 = RTCString().printf("%s%c%s", pszDropDir, RTPATH_SLASH, pszFilePath);
    315             char *pszNewUri = RTUriFileCreate(strFullPath.c_str());
    316             if (pszNewUri)
    317             {
    318                 guestUriList.append(pszNewUri);
    319                 RTStrFree(pszNewUri);
    320             }
    321         }
    322         else
    323             guestUriList.append(strUri);
    324     }
    325 
     296    DnDURIList lstURI;
     297    rc = lstURI.RootFromURIData(*ppvData, *pcbDataRecv,
     298                                0 /* fFlags */);
    326299    if (RT_SUCCESS(rc))
    327300    {
    328301        /* Cleanup the old data and write the new data back to the event. */
    329302        RTMemFree(*ppvData);
    330         RTCString newData = RTCString::join(guestUriList, "\r\n") + "\r\n";
    331 
    332         *ppvData = RTStrDupN(newData.c_str(), newData.length());
    333         *pcbDataRecv = newData.length() + 1;
     303
     304        RTCString strData = lstURI.RootToString(pszDropDir);
     305        *ppvData = RTStrDupN(strData.c_str(), strData.length());
     306        *pcbDataRecv = strData.length() + 1;
    334307    }
    335308
     
    403376                            if (RT_SUCCESS(rc))
    404377                            {
     378                                /** @todo r=andy Not very safe to assume that we were last appending to the current file. */
    405379                                rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL);
    406380                                if (RT_SUCCESS(rc))
     
    488462    Msg.cFormat.SetUInt32(0);
    489463    Msg.pvData.SetPtr(pvData, cbData);
    490     Msg.cData.SetUInt32(0);
     464    Msg.cbData.SetUInt32(0);
    491465
    492466    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    497471            || rc == VERR_BUFFER_OVERFLOW)
    498472        {
    499             /* Fetch results */
    500473            rc = Msg.uScreenId.GetUInt32(puScreenId);  AssertRC(rc);
    501474            rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
    502             rc = Msg.cData.GetUInt32(pcbDataTotal);     AssertRC(rc);
    503             /* A little bit paranoia */
     475            rc = Msg.cbData.GetUInt32(pcbDataTotal);     AssertRC(rc);
     476
    504477            AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
    505478            AssertReturn(cbData   >= *pcbDataTotal,  VERR_TOO_MUCH_DATA);
     
    526499
    527500    Msg.pvData.SetPtr(pvData, cbData);
    528     Msg.cData.SetUInt32(0);
     501    Msg.cbData.SetUInt32(0);
    529502
    530503    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    535508            || rc == VERR_BUFFER_OVERFLOW)
    536509        {
    537             /* Fetch results */
    538             rc = Msg.cData.GetUInt32(pcbDataRecv); AssertRC(rc);
    539             /* A little bit paranoia */
     510            rc = Msg.cbData.GetUInt32(pcbDataRecv); AssertRC(rc);
    540511            AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
    541512        }
     
    629600         * This keeps the actual (guest OS-)dependent client (like VBoxClient /
    630601         * VBoxTray) small by not having too much redundant code. */
    631         if (RTStrNICmp(pszFormat, "text/uri-list", *pcbFormatRecv) == 0)
     602        AssertPtr(pcbFormatRecv);
     603        if (DnDMIMEHasFileURLs(pszFormat, *pcbFormatRecv))
    632604            rc = vbglR3DnDHGProcessURIMessages(uClientId,
    633605                                               puScreenId,
     
    661633        rc = Msg.hdr.result;
    662634        if (RT_SUCCESS(rc))
    663         {
    664             /* Fetch results */
    665635            rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
    666         }
    667636    }
    668637
     
    697666        if (RT_SUCCESS(rc))
    698667        {
    699             /* Fetch results */
    700668            rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
    701669            rc = Msg.uAction.GetUInt32(puAction);      AssertRC(rc);
    702             /* A little bit paranoia */
     670
    703671            AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
    704672        }
     
    872840    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_ACK_OP;
    873841    Msg.hdr.cParms      = 1;
    874     /* Initialize parameter */
     842
    875843    Msg.uAction.SetUInt32(uAction);
    876     /* Do request */
     844
    877845    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    878846    if (RT_SUCCESS(rc))
     
    892860    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA;
    893861    Msg.hdr.cParms      = 1;
    894     /* Initialize parameter */
     862
    895863    Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
    896     /* Do request */
     864
    897865    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    898866    if (RT_SUCCESS(rc))
     
    914882    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_ACK_PENDING;
    915883    Msg.hdr.cParms      = 3;
    916     /* Initialize parameter */
     884
    917885    Msg.uDefAction.SetUInt32(uDefAction);
    918886    Msg.uAllActions.SetUInt32(uAllActions);
    919887    Msg.pFormat.SetPtr((void*)pcszFormats, (uint32_t)strlen(pcszFormats) + 1);
    920     /* Do request */
    921     int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    922     if (RT_SUCCESS(rc))
    923         rc = Msg.hdr.result;
    924 
    925     return rc;
    926 }
    927 
    928 VBGLR3DECL(int) VbglR3DnDGHSendData(uint32_t u32ClientId,
    929                                     void *pvData, uint32_t cbData)
     888
     889    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     890    if (RT_SUCCESS(rc))
     891        rc = Msg.hdr.result;
     892
     893    return rc;
     894}
     895
     896static int vbglR3DnDGHSendDataInternal(uint32_t u32ClientId,
     897                                       void *pvData, uint32_t cbData,
     898                                       uint32_t cbAdditionalData)
    930899{
    931900    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
    932     AssertReturn(cbData,    VERR_INVALID_PARAMETER);
     901    AssertReturn(cbData, VERR_INVALID_PARAMETER);
    933902
    934903    DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
     
    938907    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DATA;
    939908    Msg.hdr.cParms      = 2;
    940     Msg.uSize.SetUInt32(cbData);
    941 
    942     int rc          = VINF_SUCCESS;
    943     uint32_t cbMax  = _64K; /* Transfer max. 64K chunks per message. */
    944     uint32_t cbSent = 0;
     909
     910    /* Total amount of bytes to send (including this data block). */
     911    Msg.cbTotalBytes.SetUInt32(cbData + cbAdditionalData);
     912
     913    int rc;
     914
     915    uint32_t cbMaxChunk = _64K; /* Transfer max. 64K chunks per message. */
     916    uint32_t cbSent     = 0;
    945917
    946918    while (cbSent < cbData)
    947919    {
    948         uint32_t cbToSend = RT_MIN(cbData - cbSent, cbMax);
    949         Msg.pData.SetPtr(static_cast<uint8_t*>(pvData) + cbSent, cbToSend);
     920        uint32_t cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
     921        Msg.pvData.SetPtr(static_cast<uint8_t*>(pvData) + cbSent, cbCurChunk);
    950922
    951923        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    956928            break;
    957929
    958         cbSent += cbToSend;
     930        cbSent += cbCurChunk;
    959931    }
    960932
    961933    if (RT_SUCCESS(rc))
    962934        Assert(cbSent == cbData);
     935
     936    LogFlowFunc(("Returning rc=%Rrc, cbData=%RU32, cbAddtionalData=%RU32\n",
     937                 rc, cbData, cbAdditionalData));
     938    return rc;
     939}
     940
     941static int vbglR3DnDGHSendDir(uint32_t u32ClientId, DnDURIObject &obj)
     942{
     943    AssertReturn(obj.GetType() == DnDURIObject::Directory, VERR_INVALID_PARAMETER);
     944
     945    DragAndDropSvc::VBOXDNDGHSENDDIRMSG Msg;
     946    RT_ZERO(Msg);
     947    Msg.hdr.result      = VERR_WRONG_ORDER;
     948    Msg.hdr.u32ClientID = u32ClientId;
     949    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DIR;
     950    Msg.hdr.cParms      = 3;
     951
     952    RTCString strPath = obj.GetDestPath();
     953    LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n",
     954                 strPath.c_str(), strPath.length(), obj.GetMode()));
     955
     956    Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
     957    Msg.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
     958    Msg.fMode.SetUInt32(obj.GetMode());
     959
     960    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     961    if (RT_SUCCESS(rc))
     962        rc = Msg.hdr.result;
     963
     964    LogFlowFuncLeaveRC(rc);
     965    return rc;
     966}
     967
     968static int vbglR3DnDGHSendFile(uint32_t u32ClientId, DnDURIObject &obj)
     969{
     970    AssertReturn(obj.GetType() == DnDURIObject::File, VERR_INVALID_PARAMETER);
     971
     972    uint32_t cbBuf = _64K; /** @todo Make this configurable? */
     973    void *pvBuf = RTMemAlloc(cbBuf);
     974    if (!pvBuf)
     975        return VERR_NO_MEMORY;
     976
     977    DragAndDropSvc::VBOXDNDGHSENDFILEMSG Msg;
     978    RT_ZERO(Msg);
     979    Msg.hdr.result      = VERR_WRONG_ORDER;
     980    Msg.hdr.u32ClientID = u32ClientId;
     981    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE;
     982    Msg.hdr.cParms      = 5;
     983
     984    RTCString strPath = obj.GetDestPath();
     985    LogFlowFunc(("strFile=%s (%zu), fMode=0x%x\n",
     986                 strPath.c_str(), strPath.length(), obj.GetMode()));
     987
     988    Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
     989    Msg.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
     990    Msg.fMode.SetUInt32(obj.GetMode());
     991
     992    int rc = VINF_SUCCESS;
     993    uint32_t cbData = obj.GetSize();
     994
     995    do
     996    {
     997        uint32_t cbToRead = RT_MIN(cbData, cbBuf);
     998        uint32_t cbRead   = 0;
     999        if (cbToRead)
     1000            rc = obj.Read(pvBuf, cbToRead, &cbRead);
     1001        if (RT_SUCCESS(rc))
     1002        {
     1003             Msg.cbData.SetUInt32(cbRead);
     1004             Msg.pvData.SetPtr(pvBuf, cbRead);
     1005
     1006             rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     1007             if (RT_SUCCESS(rc))
     1008                 rc = Msg.hdr.result;
     1009        }
     1010
     1011        if (RT_FAILURE(rc))
     1012            break;
     1013
     1014        Assert(cbRead <= cbData);
     1015        cbData -= cbRead;
     1016
     1017    } while (cbData);
     1018
     1019    RTMemFree(pvBuf);
     1020
     1021    LogFlowFuncLeaveRC(rc);
     1022    return rc;
     1023}
     1024
     1025static int vbglR3DnDGHSendURIObject(uint32_t u32ClientId, DnDURIObject &obj)
     1026{
     1027    int rc;
     1028
     1029    switch (obj.GetType())
     1030    {
     1031        case DnDURIObject::Directory:
     1032            rc = vbglR3DnDGHSendDir(u32ClientId, obj);
     1033            break;
     1034
     1035        case DnDURIObject::File:
     1036            rc = vbglR3DnDGHSendFile(u32ClientId, obj);
     1037            break;
     1038
     1039        default:
     1040            AssertMsgFailed(("Type %ld not implemented\n",
     1041                             obj.GetType()));
     1042            rc = VERR_NOT_IMPLEMENTED;
     1043            break;
     1044    }
     1045
     1046    return rc;
     1047}
     1048
     1049static int vbglR3DnDGHProcessURIMessages(uint32_t u32ClientId,
     1050                                         void *pvData, uint32_t cbData)
     1051{
     1052    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     1053    AssertReturn(cbData, VERR_INVALID_PARAMETER);
     1054
     1055    RTCList<RTCString> lstPaths =
     1056        RTCString((const char *)pvData, cbData).split("\r\n");
     1057
     1058    DnDURIList lstURI;
     1059    int rc = lstURI.AppendNativePathsFromList(lstPaths, 0 /* fFlags */);
     1060    if (RT_SUCCESS(rc))
     1061    {
     1062        /* Send metadata; in this case it's the (non-recursive) file/directory
     1063         * URI list the host needs to know to initialize the drag'n drop operation. */
     1064        RTCString strRootDest = lstURI.RootToString();
     1065        Assert(strRootDest.isNotEmpty());
     1066
     1067        void *pvToSend = (void *)strRootDest.c_str();
     1068        uint32_t cbToSend = (uint32_t)strRootDest.length() + 1;
     1069
     1070        rc = vbglR3DnDGHSendDataInternal(u32ClientId, pvToSend, cbToSend,
     1071                                         /* Include total bytes of all file paths,
     1072                                          * file sizes etc. */
     1073                                         lstURI.TotalBytes());
     1074    }
     1075
     1076    if (RT_SUCCESS(rc))
     1077    {
     1078        while (!lstURI.IsEmpty())
     1079        {
     1080            DnDURIObject &nextObj = lstURI.First();
     1081
     1082            rc = vbglR3DnDGHSendURIObject(u32ClientId, nextObj);
     1083            if (RT_FAILURE(rc))
     1084                break;
     1085
     1086            lstURI.RemoveFirst();
     1087        }
     1088    }
     1089
     1090    return rc;
     1091}
     1092
     1093VBGLR3DECL(int) VbglR3DnDGHSendData(uint32_t u32ClientId,
     1094                                    const char *pszFormat,
     1095                                    void *pvData, uint32_t cbData)
     1096{
     1097    AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
     1098    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     1099    AssertReturn(cbData, VERR_INVALID_PARAMETER);
     1100
     1101    int rc;
     1102    if (DnDMIMEHasFileURLs(pszFormat, strlen(pszFormat)))
     1103    {
     1104        rc = vbglR3DnDGHProcessURIMessages(u32ClientId, pvData, cbData);
     1105    }
     1106    else
     1107        rc = vbglR3DnDGHSendDataInternal(u32ClientId, pvData, cbData,
     1108                                         0 /* cbAdditionalData */);
    9631109
    9641110    return rc;
     
    9731119    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_EVT_ERROR;
    9741120    Msg.hdr.cParms      = 1;
    975     /* Initialize parameter */
     1121
    9761122    Msg.uRC.SetUInt32(rcOp);
    977     /* Do request */
    978     int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    979     if (RT_SUCCESS(rc))
    980         rc = Msg.hdr.result;
    981 
    982     return rc;
    983 }
    984 
    985 VBGLR3DECL(int) VbglR3DnDGHSendFile(uint32_t u32ClientId, const char *pszPath)
    986 {
    987     return 0;
    988 }
    989 
     1123
     1124    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     1125    if (RT_SUCCESS(rc))
     1126        rc = Msg.hdr.result;
     1127
     1128    return rc;
     1129}
     1130
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette