VirtualBox

Ignore:
Timestamp:
Oct 6, 2015 8:52:48 PM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
103123
Message:

IPRT: Added RTUriFileCreateEx and made RTUriFileCreate assume OS specific input path like it was supposed to. Fixed DOS slash flipping.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/misc/uri.cpp

    r58066 r58067  
    116116
    117117    return pszRes;
     118}
     119
     120
     121/**
     122 * Calculates the encoded string length.
     123 *
     124 * @returns Number of chars (excluding the terminator).
     125 * @param   pszString       The string to encode.
     126 * @param   cchMax          The maximum string length (e.g. RTSTR_MAX).
     127 * @param   fEncodeDosSlash Whether to encode DOS slashes or not.
     128 */
     129static size_t rtUriCalcEncodedLength(const char *pszString, size_t cchMax, bool fEncodeDosSlash)
     130{
     131    size_t cchEncoded = 0;
     132    if (pszString)
     133    {
     134        size_t cchSrcLeft = RTStrNLen(pszString, cchMax);
     135        while (cchSrcLeft-- > 0)
     136        {
     137            char const ch = *pszString++;
     138            if (!URI_EXCLUDED(ch) || (ch == '\\' && !fEncodeDosSlash))
     139                cchEncoded += 1;
     140            else
     141                cchEncoded += 3;
     142        }
     143    }
     144    return cchEncoded;
     145}
     146
     147
     148/**
     149 * Encodes an URI into a caller allocated buffer.
     150 *
     151 * @returns IPRT status code.
     152 * @param   pszString       The string to encode.
     153 * @param   cchMax          The maximum string length (e.g. RTSTR_MAX).
     154 * @param   fEncodeDosSlash Whether to encode DOS slashes or not.
     155 * @param   pszDst          The destination buffer.
     156 * @param   cbDst           The size of the destination buffer.
     157 */
     158static int rtUriEncodeIntoBuffer(const char *pszString, size_t cchMax, bool fEncodeDosSlash, char *pszDst, size_t cbDst)
     159{
     160    AssertReturn(pszString, VERR_INVALID_POINTER);
     161
     162    /*
     163     * We do buffer size checking up front and every time we encode a special
     164     * character.  That's faster than checking for each char.
     165     */
     166    size_t cchSrcLeft = RTStrNLen(pszString, cchMax);
     167    AssertMsgReturn(cbDst > cchSrcLeft, ("cbDst=%zu cchSrcLeft=%zu\n", cbDst, cchSrcLeft), VERR_BUFFER_OVERFLOW);
     168    cbDst -= cchSrcLeft;
     169
     170    while (cchSrcLeft-- > 0)
     171    {
     172        char const ch = *pszString++;
     173        if (!URI_EXCLUDED(ch) || (ch == '\\' && !fEncodeDosSlash))
     174            *pszDst++ = ch;
     175        else
     176        {
     177            AssertReturn(cbDst >= 3, VERR_BUFFER_OVERFLOW); /* 2 extra bytes + zero terminator. */
     178            cbDst -= 2;
     179
     180            *pszDst++ = '%';
     181            ssize_t cchTmp = RTStrFormatU8(pszDst, 3, (unsigned char)ch, 16, 2, 2, RTSTR_F_CAPITAL | RTSTR_F_ZEROPAD);
     182            Assert(cchTmp == 2); NOREF(cchTmp);
     183            pszDst += 2;
     184        }
     185    }
     186
     187    *pszDst = '\0';
     188    return VINF_SUCCESS;
    118189}
    119190
     
    677748
    678749
     750RTDECL(int) RTUriFileCreateEx(const char *pszPath, uint32_t fPathStyle, char **ppszUri, size_t cbUri, size_t *pcchUri)
     751{
     752    /*
     753     * Validate and adjust input. (RTPathParse check pszPath out for us)
     754     */
     755    if (pcchUri)
     756    {
     757        AssertPtrReturn(pcchUri, VERR_INVALID_POINTER);
     758        *pcchUri = ~(size_t)0;
     759    }
     760    AssertPtrReturn(ppszUri, VERR_INVALID_POINTER);
     761    AssertReturn(!(fPathStyle & ~RTPATH_STR_F_STYLE_MASK) && fPathStyle != RTPATH_STR_F_STYLE_RESERVED, VERR_INVALID_FLAGS);
     762    if (fPathStyle == RTPATH_STR_F_STYLE_HOST)
     763        fPathStyle = RTPATH_STYLE;
     764
     765    /*
     766     * Let the RTPath code parse the stuff (no reason to duplicate path parsing
     767     * and get it slightly wrong here).
     768     */
     769    RTPATHPARSED ParsedPath;
     770    int rc = RTPathParse(pszPath, &ParsedPath, sizeof(ParsedPath), fPathStyle);
     771    if (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW)
     772    {
     773        /* Skip leading slashes. */
     774        if (ParsedPath.fProps & RTPATH_PROP_ROOT_SLASH)
     775        {
     776            if (fPathStyle == RTPATH_STR_F_STYLE_DOS)
     777                while (pszPath[0] == '/' || pszPath[0] == '\\')
     778                    pszPath++;
     779            else
     780                while (pszPath[0] == '/')
     781                    pszPath++;
     782        }
     783        const size_t cchPath = strlen(pszPath);
     784
     785        /*
     786         * Calculate the encoded length and figure destination buffering.
     787         */
     788        static const char s_szPrefix[] = "file:///";
     789        size_t const      cchPrefix    = sizeof(s_szPrefix) - (ParsedPath.fProps & RTPATH_PROP_UNC ? 2 : 1);
     790        size_t cchEncoded = rtUriCalcEncodedLength(pszPath, cchPath, fPathStyle != RTPATH_STR_F_STYLE_DOS);
     791
     792        if (pcchUri)
     793            *pcchUri = cchEncoded;
     794
     795        char  *pszDst;
     796        char  *pszFreeMe = NULL;
     797        if (!cbUri || *ppszUri == NULL)
     798        {
     799            cbUri = RT_MAX(cbUri, cchPrefix + cchEncoded + 1);
     800            *ppszUri = pszFreeMe = pszDst = RTStrAlloc(cbUri);
     801            AssertReturn(pszDst, VERR_NO_STR_MEMORY);
     802        }
     803        else if (cchEncoded < cbUri)
     804            pszDst = *ppszUri;
     805        else
     806            return VERR_BUFFER_OVERFLOW;
     807
     808        /*
     809         * Construct the URI.
     810         */
     811        memcpy(pszDst, s_szPrefix, cchPrefix);
     812        pszDst[cchPrefix] = '\0';
     813        rc = rtUriEncodeIntoBuffer(pszPath, cchPath, fPathStyle != RTPATH_STR_F_STYLE_DOS, &pszDst[cchPrefix], cbUri - cchPrefix);
     814        if (RT_SUCCESS(rc))
     815        {
     816            Assert(strlen(pszDst) == cbUri - 1);
     817            if (fPathStyle == RTPATH_STR_F_STYLE_DOS)
     818                RTPathChangeToUnixSlashes(pszDst, true /*fForce*/);
     819            return VINF_SUCCESS;
     820        }
     821
     822        AssertRC(rc); /* Impossible! rtUriCalcEncodedLength or something above is busted! */
     823        if (pszFreeMe)
     824            RTStrFree(pszFreeMe);
     825    }
     826    return rc;
     827}
     828
     829
    679830RTDECL(char *) RTUriFileCreate(const char *pszPath)
    680831{
    681     /* Empty paths are invalid. */
    682     AssertPtrReturn(pszPath, NULL);
    683     AssertReturn(*pszPath, NULL);
    684 
    685     char *pszResult = NULL;
    686     if (pszPath)
    687     {
    688         /* Check if it's an UNC path. Skip any leading slashes. */
    689         while (pszPath)
    690         {
    691             if (   *pszPath != '\\'
    692                 && *pszPath != '/')
    693                 break;
    694             pszPath++;
    695         }
    696 
    697         /* Create the percent encoded strings and calculate the necessary URI length. */
    698         char *pszPath1 = rtUriPercentEncodeN(pszPath, RTSTR_MAX);
    699         if (pszPath1)
    700         {
    701             /* Always change DOS slashes to Unix slashes. */
    702             RTPathChangeToUnixSlashes(pszPath1, true); /** @todo Flags? */
    703 
    704             size_t cbSize = 7 /* file:// */ + strlen(pszPath1) + 1; /* plus zero byte */
    705             if (pszPath1[0] != '/')
    706                 ++cbSize;
    707             char *pszTmp = pszResult = RTStrAlloc(cbSize);
    708             if (pszResult)
    709             {
    710                 /* Compose the target URI string. */
    711                 *pszTmp = '\0';
    712                 RTStrCatP(&pszTmp, &cbSize, "file://");
    713                 if (pszPath1[0] != '/')
    714                     RTStrCatP(&pszTmp, &cbSize, "/");
    715                 RTStrCatP(&pszTmp, &cbSize, pszPath1);
    716             }
    717             RTStrFree(pszPath1);
    718         }
    719     }
    720 
    721     return pszResult;
     832    char *pszUri = NULL;
     833    int rc = RTUriFileCreateEx(pszPath, RTPATH_STR_F_STYLE_HOST, &pszUri, 0 /*cbUri*/, NULL /*pcchUri*/);
     834    if (RT_SUCCESS(rc))
     835        return pszUri;
     836    return NULL;
    722837}
    723838
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