/* static */
int DnDURIObject::RebaseURIPath(RTCString &strPathAbs,
                                const RTCString &strBaseOld /* = "" */,
                                const RTCString &strBaseNew /* = "" */)
{
    char *pszPath = RTUriFilePath(strPathAbs.c_str());
    if (!pszPath) /* No URI? */
         pszPath = RTStrDup(strPathAbs.c_str());

    int rc;

    if (pszPath)
    {
        const char *pszPathStart = pszPath;
        const char *pszBaseOld = strBaseOld.c_str();
        if (   pszBaseOld
            && RTPathStartsWith(pszPath, pszBaseOld))
        {
            pszPathStart += strlen(pszBaseOld);
        }

        rc = VINF_SUCCESS;

        if (RT_SUCCESS(rc))
        {
            char *pszPathNew = RTPathJoinA(strBaseNew.c_str(), pszPathStart);
            if (pszPathNew)
            {
                char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */,
                                               pszPathNew /* pszPath */,
                                               NULL /* pszQuery */, NULL /* pszFragment */);
                if (pszPathURI)
                {
                    LogFlowFunc(("Rebasing \"%s\" to \"%s\"\n", strPathAbs.c_str(), pszPathURI));

                    strPathAbs = RTCString(pszPathURI) + "\r\n";
                    RTStrFree(pszPathURI);
                }
                else
                    rc = VERR_INVALID_PARAMETER;

                RTStrFree(pszPathNew);
            }
            else
                rc = VERR_NO_MEMORY;
        }

        RTStrFree(pszPath);
    }
    else
        rc = VERR_NO_MEMORY;

    return rc;
}
Exemple #2
0
int DnDURIList::AppendURIPath(const char *pszURI, uint32_t fFlags)
{
    AssertPtrReturn(pszURI, VERR_INVALID_POINTER);

    /** @todo Check for string termination?  */
#ifdef DEBUG_andy
    LogFlowFunc(("pszPath=%s, fFlags=0x%x\n", pszURI, fFlags));
#endif
    int rc = VINF_SUCCESS;

    /* Query the path component of a file URI. If this hasn't a
     * file scheme NULL is returned. */
    char *pszFilePath = RTUriFilePath(pszURI, URI_FILE_FORMAT_AUTO);
    if (pszFilePath)
    {
        /* Add the path to our internal file list (recursive in
         * the case of a directory). */
        size_t cbPathLen = RTPathStripTrailingSlash(pszFilePath);
        if (cbPathLen)
        {
            char *pszFileName = RTPathFilename(pszFilePath);
            if (pszFileName)
            {
                Assert(pszFileName >= pszFilePath);
                size_t cbBase = (fFlags & DNDURILIST_FLAGS_ABSOLUTE_PATHS)
                              ? 0 /* Use start of path as root. */
                              : pszFileName - pszFilePath;
                char *pszRoot = &pszFilePath[cbBase];
                m_lstRoot.append(pszRoot);
#ifdef DEBUG_andy
                LogFlowFunc(("pszFilePath=%s, pszFileName=%s, pszRoot=%s\n",
                             pszFilePath, pszFileName, pszRoot));
#endif
                rc = appendPathRecursive(pszFilePath, cbBase,
                                         fFlags);
            }
            else
                rc = VERR_NOT_FOUND;
        }
        else
            rc = VERR_INVALID_PARAMETER;

        RTStrFree(pszFilePath);
    }
    else
        rc = VERR_INVALID_PARAMETER;

    LogFlowFuncLeaveRC(rc);
    return rc;
}
Exemple #3
0
int DnDURIList::RootFromURIData(const void *pvData, size_t cbData, uint32_t fFlags)
{
    Assert(fFlags == 0); RT_NOREF1(fFlags);
    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
    AssertReturn(cbData, VERR_INVALID_PARAMETER);

    if (!RTStrIsValidEncoding(static_cast<const char *>(pvData)))
        return VERR_INVALID_PARAMETER;

    RTCList<RTCString> lstURI =
        RTCString(static_cast<const char *>(pvData), cbData - 1).split("\r\n");
    if (lstURI.isEmpty())
        return VINF_SUCCESS;

    int rc = VINF_SUCCESS;

    for (size_t i = 0; i < lstURI.size(); ++i)
    {
        /* Query the path component of a file URI. If this hasn't a
         * file scheme, NULL is returned. */
        const char *pszURI = lstURI.at(i).c_str();
        char *pszFilePath = RTUriFilePath(pszURI);
#ifdef DEBUG_andy
        LogFlowFunc(("pszURI=%s, pszFilePath=%s\n", pszURI, pszFilePath));
#endif
        if (pszFilePath)
        {
            rc = DnDPathSanitize(pszFilePath, strlen(pszFilePath));
            if (RT_SUCCESS(rc))
            {
                m_lstRoot.append(pszFilePath);
                m_cTotal++;
            }

            RTStrFree(pszFilePath);
        }
        else
            rc = VERR_INVALID_PARAMETER;

        if (RT_FAILURE(rc))
            break;
    }

    return rc;
}
static int vbglR3DnDHGProcessURIMessages(uint32_t   uClientId,
                                         uint32_t  *puScreenId,
                                         char      *pszFormat,
                                         uint32_t   cbFormat,
                                         uint32_t  *pcbFormatRecv,
                                         void     **ppvData,
                                         uint32_t   cbData,
                                         size_t    *pcbDataRecv)
{
    /* Make a string list out of the uri data. */
    RTCList<RTCString> uriList = RTCString(static_cast<char*>(*ppvData), *pcbDataRecv - 1).split("\r\n");
    if (uriList.isEmpty())
        return VINF_SUCCESS;

    uint32_t cbTmpData = _1M * 10;
    void *pvTmpData = RTMemAlloc(cbTmpData);
    if (!pvTmpData)
        return VERR_NO_MEMORY;

    /* Create and query the drop target directory. */
    char pszDropDir[RTPATH_MAX];
    int rc = vbglR3DnDCreateDropDir(pszDropDir, sizeof(pszDropDir));
    if (RT_FAILURE(rc))
    {
        RTMemFree(pvTmpData);
        return rc;
    }

    /* Patch the old drop data with the new drop directory, so the drop target
     * can find the files. */
    RTCList<RTCString> guestUriList;
    for (size_t i = 0; i < uriList.size(); ++i)
    {
        const RTCString &strUri = uriList.at(i);
        /* Query the path component of a file URI. If this hasn't a
         * file scheme, null is returned. */
        if (char *pszFilePath = RTUriFilePath(strUri.c_str(), URI_FILE_FORMAT_AUTO))
        {
            RTCString strFullPath = RTCString().printf("%s%c%s", pszDropDir, RTPATH_SLASH, pszFilePath);
            char *pszNewUri = RTUriFileCreate(strFullPath.c_str());
            if (pszNewUri)
            {
                guestUriList.append(pszNewUri);
                RTStrFree(pszNewUri);
            }
        }
        else
            guestUriList.append(strUri);
    }

    /* Cleanup the old data and write the new data back to the event. */
    RTMemFree(*ppvData);
    RTCString newData = RTCString::join(guestUriList, "\r\n") + "\r\n";
    *ppvData = RTStrDupN(newData.c_str(), newData.length());
    *pcbDataRecv = newData.length() + 1;

    /* Lists for holding created files & directories in the case of a
     * rollback. */
    RTCList<RTCString> guestDirList;
    RTCList<RTCString> guestFileList;
    char pszPathname[RTPATH_MAX];
    uint32_t cbPathname = 0;
    bool fLoop = true;
    do
    {
        uint32_t uNextMsg;
        uint32_t cNextParms;
        rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false);
        DO(("%Rrc - %d\n", rc , uNextMsg));
        if (RT_SUCCESS(rc))
        {
            switch(uNextMsg)
            {
                case DragAndDropSvc::HOST_DND_HG_SND_DIR:
                {
                    uint32_t fMode = 0;
                    rc = vbglR3DnDHGProcessSendDirMessage(uClientId,
                                                          pszPathname,
                                                          sizeof(pszPathname),
                                                          &cbPathname,
                                                          &fMode);
                    if (RT_SUCCESS(rc))
                    {
                        DO(("Got drop dir: %s - %o - %Rrc\n", pszPathname, fMode, rc));
                        char *pszNewDir = RTPathJoinA(pszDropDir, pszPathname);
                        rc = RTDirCreate(pszNewDir, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU, 0);
                        if (!guestDirList.contains(pszNewDir))
                            guestDirList.append(pszNewDir);
                    }
                    break;
                }
                case DragAndDropSvc::HOST_DND_HG_SND_FILE:
                {
                    uint32_t cbDataRecv;
                    uint32_t fMode = 0;
                    rc = vbglR3DnDHGProcessSendFileMessage(uClientId,
                                                           pszPathname,
                                                           sizeof(pszPathname),
                                                           &cbPathname,
                                                           pvTmpData,
                                                           cbTmpData,
                                                           &cbDataRecv,
                                                           &fMode);
                    if (RT_SUCCESS(rc))
                    {
                        char *pszNewFile = RTPathJoinA(pszDropDir, pszPathname);
                        DO(("Got drop file: %s - %d - %o - %Rrc\n", pszPathname, cbDataRecv, fMode, rc));
                        RTFILE hFile;
                        rc = RTFileOpen(&hFile, pszNewFile, RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_DENY_ALL | RTFILE_O_OPEN_CREATE);
                        if (RT_SUCCESS(rc))
                        {
                            rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL);
                            if (RT_SUCCESS(rc))
                            {
                                rc = RTFileWrite(hFile, pvTmpData, cbDataRecv, 0);
                                /* Valid UNIX mode? */
                                if (   RT_SUCCESS(rc)
                                    && (fMode & RTFS_UNIX_MASK))
                                    rc = RTFileSetMode(hFile, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
                            }
                            RTFileClose(hFile);
                            if (!guestFileList.contains(pszNewFile))
                                guestFileList.append(pszNewFile);
                        }
                    }
                    break;
                }
                case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
                {
                    rc = vbglR3DnDHGProcessCancelMessage(uClientId);
                    if (RT_SUCCESS(rc))
                        rc = VERR_CANCELLED;
                    /* Break out of the loop. */
                }
                default: fLoop = false; break;
            }
        } else
        {
            if (rc == VERR_NO_DATA)
                rc = VINF_SUCCESS;
            break;
        }
    }while(fLoop);

    RTMemFree(pvTmpData);
    /* Cleanup on failure or if the user has canceled. */
    if (RT_FAILURE(rc))
    {
        /* Remove any stuff created. */
        for (size_t i = 0; i < guestFileList.size(); ++i)
            RTFileDelete(guestFileList.at(i).c_str());
        for (size_t i = 0; i < guestDirList.size(); ++i)
            RTDirRemove(guestDirList.at(i).c_str());
        RTDirRemove(pszDropDir);
    }

    return rc;
}
/**
 * Retrieves the data stored in this object and store the result in
 * pMedium.
 *
 * @return  IPRT status code.
 * @return  HRESULT
 * @param   pFormatEtc
 * @param   pMedium
 */
STDMETHODIMP UIDnDDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
{
    AssertPtrReturn(pFormatEtc, DV_E_FORMATETC);
    AssertPtrReturn(pMedium, DV_E_FORMATETC);

    HRESULT hr = DV_E_FORMATETC;

    LPFORMATETC pThisFormat = NULL;
    LPSTGMEDIUM pThisMedium = NULL;

    LogFlowThisFunc(("\n"));

    /* Format supported? */
    ULONG lIndex;
    if (   LookupFormatEtc(pFormatEtc, &lIndex)
        && lIndex < m_cFormats) /* Paranoia. */
    {
        pThisMedium = &m_pStgMedium[lIndex];
        AssertPtr(pThisMedium);
        pThisFormat = &m_pFormatEtc[lIndex];
        AssertPtr(pThisFormat);

        LogFlowThisFunc(("pThisMedium=%p, pThisFormat=%p\n", pThisMedium, pThisFormat));
        LogFlowThisFunc(("mStatus=%RU32\n", m_enmStatus));
        switch (m_enmStatus)
        {
            case DnDDataObjectStatus_Dropping:
            {
#if 0
                LogRel3(("DnD: Dropping\n"));
                LogFlowFunc(("Waiting for event ...\n"));
                int rc2 = RTSemEventWait(m_SemEvent, RT_INDEFINITE_WAIT);
                LogFlowFunc(("rc=%Rrc, mStatus=%RU32\n", rc2, m_enmStatus));
#endif
                break;
            }

            case DnDDataObjectStatus_Dropped:
            {
                LogRel3(("DnD: Dropped\n"));
                LogRel3(("DnD: cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32\n",
                         pThisFormat->cfFormat, UIDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
                         pThisFormat->tymed, pThisFormat->dwAspect));
                LogRel3(("DnD: Got strFormat=%s, pvData=%p, cbData=%RU32\n",
                         m_strFormat.toUtf8().constData(), m_pvData, m_cbData));

                QVariant::Type vaType;
                QString strMIMEType;
                if (    (pFormatEtc->tymed & TYMED_HGLOBAL)
                     && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
                     && (   pFormatEtc->cfFormat == CF_TEXT
                         || pFormatEtc->cfFormat == CF_UNICODETEXT)
                   )
                {
                    strMIMEType = "text/plain"; /** @todo Indicate UTF8 encoding? */
                    vaType = QVariant::String;
                }
                else if (   (pFormatEtc->tymed & TYMED_HGLOBAL)
                         && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
                         && (pFormatEtc->cfFormat == CF_HDROP))
                {
                    strMIMEType = "text/uri-list";
                    vaType = QVariant::StringList;
                }
#if 0 /* More formats; not needed right now. */
                else if (   (pFormatEtc->tymed & TYMED_ISTREAM)
                        && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
                        && (pFormatEtc->cfFormat == CF_FILECONTENTS))
                {

                }
                else if  (   (pFormatEtc->tymed & TYMED_HGLOBAL)
                          && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
                          && (pFormatEtc->cfFormat == CF_FILEDESCRIPTOR))
                {

                }
                else if (   (pFormatEtc->tymed & TYMED_HGLOBAL)
                         && (pFormatEtc->cfFormat == CF_PREFERREDDROPEFFECT))
                {
                    HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, sizeof(DWORD));
                    DWORD *pdwEffect = (DWORD *)GlobalLock(hData);
                    AssertPtr(pdwEffect);
                    *pdwEffect = DROPEFFECT_COPY;
                    GlobalUnlock(hData);

                    pMedium->hGlobal = hData;
                    pMedium->tymed = TYMED_HGLOBAL;
                }
#endif
                LogRel3(("DnD: strMIMEType=%s, vaType=%ld\n", strMIMEType.toUtf8().constData(), vaType));

                int rc;

                if (!m_fDataRetrieved)
                {
                    if (m_pDnDHandler)
                    {
                        rc = m_pDnDHandler->retrieveData(Qt::CopyAction,
                                                         strMIMEType, vaType, m_vaData);
                    }
                    else
                        rc = VERR_NOT_FOUND;

                    m_fDataRetrieved = true;
                    LogFlowFunc(("Retrieving data ended with %Rrc\n", rc));
                }
                else /* Data already been retrieved. */
                    rc = VINF_SUCCESS;

                if (   RT_SUCCESS(rc)
                    && m_vaData.isValid())
                {
                    if (   strMIMEType.startsWith("text/uri-list")
                               /* One item. */
                        && (   m_vaData.canConvert(QVariant::String)
                               /* Multiple items. */
                            || m_vaData.canConvert(QVariant::StringList))
                       )
                    {
                        QStringList lstFilesURI = m_vaData.toStringList();
                        QStringList lstFiles;
                        for (size_t i = 0; i < lstFilesURI.size(); i++)
                        {
                            char *pszFilePath = RTUriFilePath(lstFilesURI.at(i).toUtf8().constData());
                            if (pszFilePath)
                            {
                                lstFiles.append(pszFilePath);
                                RTStrFree(pszFilePath);
                            }
                            else /* Unable to parse -- refuse entire request. */
                            {
                                lstFiles.clear();
                                rc = VERR_INVALID_PARAMETER;
                                break;
                            }
                        }

                        size_t cFiles = lstFiles.size();
                        LogFlowThisFunc(("Files (%zu)\n", cFiles));
                        if (   RT_SUCCESS(rc)
                            && cFiles)
                        {
                            size_t cchFiles = 0; /* Number of characters. */
                            for (size_t i = 0; i < cFiles; i++)
                            {
                                const char *pszFile = lstFiles.at(i).toUtf8().constData();
                                cchFiles += strlen(pszFile);
                                cchFiles += 1; /* Terminating '\0'. */
                                LogFlowThisFunc(("\tFile: %s (cchFiles=%zu)\n", pszFile, cchFiles));
                            }

                            /* List termination with '\0'. */
                            cchFiles++;

                            size_t cbBuf = sizeof(DROPFILES) + (cchFiles * sizeof(RTUTF16));
                            DROPFILES *pDropFiles = (DROPFILES *)RTMemAllocZ(cbBuf);
                            if (pDropFiles)
                            {
                                /* Put the files list right after our DROPFILES structure. */
                                pDropFiles->pFiles = sizeof(DROPFILES); /* Offset to file list. */
                                pDropFiles->fWide  = 1;                 /* We use Unicode. Always. */

                                uint8_t *pCurFile = (uint8_t *)pDropFiles + pDropFiles->pFiles;
                                AssertPtr(pCurFile);

                                LogFlowThisFunc(("Encoded:\n"));
                                for (size_t i = 0; i < cFiles; i++)
                                {
                                    const char *pszFile = lstFiles.at(i).toUtf8().constData();
                                    Assert(strlen(pszFile));

                                    size_t cchCurFile;
                                    PRTUTF16 pwszFile;
                                    rc = RTStrToUtf16(pszFile, &pwszFile);
                                    if (RT_SUCCESS(rc))
                                    {
                                        cchCurFile = RTUtf16Len(pwszFile);
                                        Assert(cchCurFile);
                                        memcpy(pCurFile, pwszFile, cchCurFile * sizeof(RTUTF16));
                                        RTUtf16Free(pwszFile);
                                    }
                                    else
                                        break;

                                    pCurFile += cchCurFile * sizeof(RTUTF16);

                                    /* Terminate current file name. */
                                    *pCurFile = L'\0';
                                    pCurFile += sizeof(RTUTF16);

                                    LogFlowThisFunc(("\t#%zu: cchCurFile=%zu\n", i, cchCurFile));
                                }

                                if (RT_SUCCESS(rc))
                                {
                                    *pCurFile = L'\0'; /* Final list terminator. */

                                    /*
                                     * Fill out the medium structure we're going to report back.
                                     */
                                    pMedium->tymed          = TYMED_HGLOBAL;
                                    pMedium->pUnkForRelease = NULL;
                                    pMedium->hGlobal        = GlobalAlloc(  GMEM_ZEROINIT
                                                                          | GMEM_MOVEABLE
                                                                          | GMEM_DDESHARE, cbBuf);
                                    if (pMedium->hGlobal)
                                    {
                                        LPVOID pvMem = GlobalLock(pMedium->hGlobal);
                                        if (pvMem)
                                        {
                                            memcpy(pvMem, pDropFiles, cbBuf);
                                            GlobalUnlock(pMedium->hGlobal);

                                            hr = S_OK;
                                        }
                                        else
                                            rc = VERR_ACCESS_DENIED;
                                    }
                                    else
                                        rc = VERR_NO_MEMORY;

                                    LogFlowThisFunc(("Copying to TYMED_HGLOBAL (%zu bytes): %Rrc\n", cbBuf, rc));
                                }

                                RTMemFree(pDropFiles);
                            }
                            else
                                rc = VERR_NO_MEMORY;

                            if (RT_FAILURE(rc))
                                LogFlowThisFunc(("Failed with %Rrc\n", rc));
                        }
                    }
                    else if (   strMIMEType.startsWith("text/plain")
                             && m_vaData.canConvert(QVariant::String))
                    {
                        const bool fUnicode = pFormatEtc->cfFormat == CF_UNICODETEXT;
                        const size_t cbCh   = fUnicode
                                            ? sizeof(WCHAR) : sizeof(char);

                        QString strText = m_vaData.toString();
                        size_t cbSrc = strText.length() * cbCh;
                        Assert(cbSrc);
                        LPCVOID pvSrc = fUnicode
                                      ? (void *)strText.unicode()
                                      : (void *)strText.toUtf8().constData();
                        AssertPtr(pvSrc);

                        LogFlowFunc(("pvSrc=0x%p, cbSrc=%zu, cbCh=%zu, fUnicode=%RTbool\n",
                                     pvSrc, cbSrc, cbCh, fUnicode));

                        pMedium->tymed          = TYMED_HGLOBAL;
                        pMedium->pUnkForRelease = NULL;
                        pMedium->hGlobal        = GlobalAlloc(GHND | GMEM_SHARE, cbSrc);
                        if (pMedium->hGlobal)
                        {
                            LPVOID pvDst = GlobalLock(pMedium->hGlobal);
                            if (pvDst)
                            {
                                memcpy(pvDst, pvSrc, cbSrc);
                                GlobalUnlock(pMedium->hGlobal);
                            }
                            else
                                rc = VERR_ACCESS_DENIED;

                            hr = S_OK;
                        }
                        else
                            hr  = VERR_NO_MEMORY;
                    }
                    else
                        LogRel2(("DnD: MIME type '%s' not supported\n", strMIMEType.toUtf8().constData()));

                    LogFlowThisFunc(("Handling formats ended with rc=%Rrc\n", rc));
                }

                break;
            }

            default:
                break;
        }
    }

    /*
     * Fallback in error case.
     */
    if (FAILED(hr))
    {
        if (pThisMedium)
        {
            switch (pThisMedium->tymed)
            {

            case TYMED_HGLOBAL:
                pMedium->hGlobal = (HGLOBAL)OleDuplicateData(pThisMedium->hGlobal,
                                                             pThisFormat->cfFormat,
                                                             0 /* Flags */);
                break;

            default:
                break;
            }
        }

        if (pFormatEtc)
            pMedium->tymed = pFormatEtc->tymed;

        pMedium->pUnkForRelease = NULL;
    }

    LogFlowThisFunc(("Returning hr=%Rhrc\n", hr));
    return hr;
}
/*
 * This class is a meta message class. It doesn't consist of any own message
 * data, but handle the meta info, the data itself as well any files or
 * directories which have to be transfered to the guest.
 */
DnDHGSendDataMessage::DnDHGSendDataMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[], PFNDNDPROGRESS pfnProgressCallback, void *pvProgressUser)
  : m_cbAll(0)
  , m_cbTransfered(0)
  , m_pfnProgressCallback(pfnProgressCallback)
  , m_pvProgressUser(pvProgressUser)
{
    RTCString strNewUris;
    /* Check the format for any uri type. */
    if (hasFileUrls(static_cast<const char*>(paParms[1].u.pointer.addr), paParms[1].u.pointer.size))
    {
        DO(("old data '%s'\n", (char*)paParms[3].u.pointer.addr));
        /* The list is separated by newline (Even if only one file is
         * listed). */
        RTCList<RTCString> oldUriList = RTCString(static_cast<const char*>(paParms[3].u.pointer.addr), paParms[3].u.pointer.size).split("\r\n");
        if (!oldUriList.isEmpty())
        {
            RTCList<RTCString> newUriList;
            for (size_t i = 0; i < oldUriList.size(); ++i)
            {
                const RTCString &strUri = oldUriList.at(i);
                /* Query the path component of a file URI. If this hasn't a
                 * file scheme null is returned. */
                if (char *pszFilePath = RTUriFilePath(strUri.c_str(), URI_FILE_FORMAT_AUTO))
                {
                    /* Add the path to our internal file list (recursive in
                     * the case of a directory). */
                    if (char *pszFilename = RTPathFilename(pszFilePath))
                    {
                        char *pszNewUri = RTUriFileCreate(pszFilename);
                        if (pszNewUri)
                        {
                            newUriList.append(pszNewUri);
                            RTStrFree(pszNewUri);
                            buildFileTree(pszFilePath, pszFilename - pszFilePath);
                        }
                    }
                    RTStrFree(pszFilePath);
                }
                else
                    newUriList.append(strUri);
            }
            /* We have to change the actual DnD data. Remove any host paths and
             * just decode the filename into the new data. The guest tools will
             * add the correct path again, before sending the DnD drop event to
             * some window. */
            strNewUris = RTCString::join(newUriList, "\r\n") + "\r\n";
            /* Remark: We don't delete the old pointer here, cause this is done
             * by the caller. We just use the RTString data, which has the
             * scope of this ctor. This is enough cause the data is copied in
             * the DnDHGSendDataMessagePrivate anyway. */
            paParms[3].u.pointer.addr = (void*)strNewUris.c_str();
            paParms[3].u.pointer.size = strNewUris.length() + 1;
            paParms[4].u.uint32       = strNewUris.length() + 1;
        }
    }
    /* Add the size of the data to the todo list. */
    m_cbAll += paParms[4].u.uint32;
    /* The first message is the meta info for the data and the data itself. */
    m_pNextPathMsg = new DnDHGSendDataMessagePrivate(uMsg, cParms, paParms, &DnDHGSendDataMessage::progressCallback, this);

    DO(("new data '%s'\n", (char*)paParms[3].u.pointer.addr));
    DO(("cbAll: %u\n", m_cbAll));
    DO(("cbData: %u\n", paParms[4].u.uint32));

    for (size_t i = 0; i < m_uriList.size(); ++i)
        DO(("file: %s : %s - %o - %ld\n", m_uriList.at(i).m_strHostPath.c_str(), m_uriList.at(i).m_strGuestPath.c_str(), m_uriList.at(i).m_fMode, m_uriList.at(i).m_cbSize));
}