VirtualBox

Ignore:
Timestamp:
Sep 11, 2015 2:49:21 PM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
102634
Message:

RTUri: Preps for parsing the authority bits into smaller pieces for cURL proxy config.

File:
1 edited

Legend:

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

    r57358 r57720  
    3131#include <iprt/uri.h>
    3232
     33#include <iprt/assert.h>
     34#include <iprt/ctype.h>
     35#include <iprt/path.h>
    3336#include <iprt/string.h>
    34 #include <iprt/mem.h>
    35 #include <iprt/path.h>
    36 #include <iprt/stream.h>
    3737
    3838/* General URI format:
     
    4747*/
    4848
     49/**
     50 * Parsed URI.
     51 */
     52typedef struct RTURIPARSED
     53{
     54    /** RTURIPARSED_F_XXX. */
     55    uint32_t    fFlags;
     56
     57    /** The length of the scheme. */
     58    size_t      cchScheme;
     59
     60    /** The offset into the string of the authority. */
     61    size_t      offAuthority;
     62    /** The authority length.
     63     * @remarks The authority component can be zero length, so to check whether
     64     *          it's there or not consult RTURIPARSED_F_HAVE_AUTHORITY. */
     65    size_t      cchAuthority;
     66
     67    /** The offset into the string of the path. */
     68    size_t      offPath;
     69    /** The length of the path. */
     70    size_t      cchPath;
     71
     72    /** The offset into the string of the query. */
     73    size_t      offQuery;
     74    /** The length of the query. */
     75    size_t      cchQuery;
     76
     77    /** The offset into the string of the fragment. */
     78    size_t      offFragment;
     79    /** The length of the fragment. */
     80    size_t      cchFragment;
     81
     82    /** @name Authority subdivisions
     83     * @{ */
     84    /** If there is a userinfo part, this is the start of it. Otherwise it's the
     85     * same as offAuthorityHost. */
     86    size_t      offAuthorityUsername;
     87    /** The length of the username (zero if not present). */
     88    size_t      cchAuthorityUsername;
     89    /** If there is a userinfo part containing a password, this is the start of it.
     90     * Otherwise it's the same as offAuthorityHost. */
     91    size_t      offAuthorityPassword;
     92    /** The length of the password (zero if not present). */
     93    size_t      cchAuthorityPassword;
     94    /** The offset of the host part of the authority. */
     95    size_t      offAuthorityHost;
     96    /** The length of the host part of the authority. */
     97    size_t      cchAuthorityHost;
     98    /** The authority port number, UINT32_MAX if not present. */
     99    uint32_t    uAuthorityPort;
     100    /** @} */
     101} RTURIPARSED;
     102/** Pointer to a parsed URI. */
     103typedef RTURIPARSED *PRTURIPARSED;
     104/** Set if the URI contains escaped characters. */
     105#define RTURIPARSED_F_CONTAINS_ESCAPED_CHARS        UINT32_C(0x00000001)
     106/** Set if the URI have an authority component.  Necessary since the authority
     107 * component can have a zero length. */
     108#define RTURIPARSED_F_HAVE_AUTHORITY                UINT32_C(0x00000002)
     109
     110
    49111
    50112/*********************************************************************************************************************************
    51 *   Private RTUri helper                                                                                                         *
     113*   Internal Functions                                                                                                           *
    52114*********************************************************************************************************************************/
    53115
    54 /* The following defines characters which have to be % escaped:
    55    control = 00-1F
    56    space   = ' '
    57    delims  = '<' , '>' , '#' , '%' , '"'
    58    unwise  = '{' , '}' , '|' , '\' , '^' , '[' , ']' , '`'
    59 */
     116/**
     117 * The following defines characters which have to be % escaped:
     118 *  control = 00-1F
     119 *  space   = ' '
     120 *  delims  = '<' , '>' , '#' , '%' , '"'
     121 *  unwise  = '{' , '}' , '|' , '\' , '^' , '[' , ']' , '`'
     122 */
    60123#define URI_EXCLUDED(a) \
    61      ((a) >= 0x0  && (a) <= 0x20) \
    62   || ((a) >= 0x5B && (a) <= 0x5E) \
    63   || ((a) >= 0x7B && (a) <= 0x7D) \
    64   || (a) == '<' || (a) == '>' || (a) == '#' \
    65   || (a) == '%' || (a) == '"' || (a) == '`'
     124  (   ((a) >= 0x0  && (a) <= 0x20) \
     125   || ((a) >= 0x5B && (a) <= 0x5E) \
     126   || ((a) >= 0x7B && (a) <= 0x7D) \
     127   || (a) == '<' || (a) == '>' || (a) == '#' \
     128   || (a) == '%' || (a) == '"' || (a) == '`' )
    66129
    67130static char *rtUriPercentEncodeN(const char *pszString, size_t cchMax)
     
    74137    size_t cbLen = RT_MIN(strlen(pszString), cchMax);
    75138    /* The new string can be max 3 times in size of the original string. */
    76     char *pszNew = (char*)RTMemAlloc(cbLen * 3 + 1);
     139    char *pszNew = RTStrAlloc(cbLen * 3 + 1);
    77140    if (!pszNew)
    78141        return NULL;
     142
    79143    char *pszRes = NULL;
    80144    size_t iIn = 0;
    81145    size_t iOut = 0;
    82     while(iIn < cbLen)
     146    while (iIn < cbLen)
    83147    {
    84148        if (URI_EXCLUDED(pszString[iIn]))
     
    117181        return NULL;
    118182
    119     int rc = VINF_SUCCESS;
    120     size_t cbLen = RT_MIN(strlen(pszString), cchMax);
    121183    /* The new string can only get smaller. */
    122     char *pszNew = (char*)RTMemAlloc(cbLen + 1);
     184    size_t cchLen = strlen(pszString);
     185    cchLen = RT_MIN(cchLen, cchMax);
     186    char *pszNew = RTStrAlloc(cchLen + 1);
    123187    if (!pszNew)
    124188        return NULL;
     189
     190    int rc = VINF_SUCCESS;
    125191    char *pszRes = NULL;
    126192    size_t iIn = 0;
    127193    size_t iOut = 0;
    128     while(iIn < cbLen)
     194    while (iIn < cchLen)
    129195    {
    130196        if (pszString[iIn] == '%')
     
    169235static bool rtUriFindSchemeEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
    170236{
     237    /* The scheme has to end with ':'. */
    171238    size_t i = iStart;
    172     /* The scheme has to end with ':'. */
    173     while(i < iStart + cbLen)
     239    while (i < iStart + cbLen)
    174240    {
    175241        if (pszUri[i] == ':')
     
    199265static bool rtUriFindAuthorityEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
    200266{
     267    /* The authority can end with '/' || '?' || '#'. */
    201268    size_t i = iStart;
    202     /* The authority can end with '/' || '?' || '#'. */
    203     while(i < iStart + cbLen)
     269    while (i < iStart + cbLen)
    204270    {
    205271        if (   pszUri[i] == '/'
     
    224290        return true;
    225291    }
     292
    226293    /* '?' || '#' means there is no path. */
    227294    if (   cbLen >= 1
     
    229296            || pszUri[iStart] == '#'))
    230297        return false;
     298
    231299    /* All other values are allowed. */
    232300    *piStart = iStart;
     
    236304static bool rtUriFindPathEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
    237305{
     306    /* The path can end with '?' || '#'. */
    238307    size_t i = iStart;
    239     /* The path can end with '?' || '#'. */
    240     while(i < iStart + cbLen)
     308    while (i < iStart + cbLen)
    241309    {
    242310        if (   pszUri[i] == '?'
     
    251319}
    252320
    253 static bool rtUriCheckQueryStart(const char *pszUri, size_t iStart, size_t cbLen, size_t *piStart)
    254 {
    255     /* The query start with a '?'. */
    256     if (   cbLen >= 1
    257         && pszUri[iStart] == '?')
    258     {
    259         *piStart = iStart + 1; /* Excluding '?' */
    260         return true;
    261     }
    262     return false;
    263 }
    264 
    265 static bool rtUriFindQueryEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
    266 {
    267     size_t i = iStart;
    268     /* The query can end with '?' || '#'. */
    269     while(i < iStart + cbLen)
    270     {
    271         if (pszUri[i] == '#')
    272         {
    273             *piEnd = i;
    274             return true;
    275         }
    276         ++i;
    277     }
    278     return false;
    279 }
    280 
    281 static bool rtUriCheckFragmentStart(const char *pszUri, size_t iStart, size_t cbLen, size_t *piStart)
    282 {
    283     /* The fragment start with a '#'. */
    284     if (   cbLen >= 1
    285         && pszUri[iStart] == '#')
    286     {
    287         *piStart = iStart + 1; /* Excluding '#' */
    288         return true;
    289     }
    290     return false;
     321static int rtUriParse(const char *pszUri, PRTURIPARSED pParsed)
     322{
     323    /*
     324     * Validate the input and clear the output.
     325     */
     326    AssertPtrReturn(pParsed, VERR_INVALID_POINTER);
     327    RT_ZERO(*pParsed);
     328    pParsed->uAuthorityPort = UINT32_MAX;
     329
     330    AssertPtrReturn(pszUri, VERR_INVALID_POINTER);
     331    size_t const cchUri = strlen(pszUri);
     332    if (RT_LIKELY(cchUri >= 3)) { /* likely */ }
     333    else return cchUri ? VERR_URI_TOO_SHORT : VERR_URI_EMPTY;
     334
     335    /*
     336     * RFC-3986, section 3.1:
     337     *      scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
     338     *
     339     * The scheme ends with a ':', which we also skip here.
     340     */
     341    size_t off = 0;
     342    char ch = pszUri[off++];
     343    if (RT_LIKELY(RT_C_IS_ALPHA(ch))) { /* likely */ }
     344    else return VERR_URI_INVALID_SCHEME;
     345    for (;;)
     346    {
     347        ch = pszUri[off];
     348        if (ch == ':')
     349            break;
     350        if (RT_LIKELY(RT_C_IS_ALNUM(ch) || ch == '.' || ch == '-' || ch == '+')) { /* likely */ }
     351        else return VERR_URI_INVALID_SCHEME;
     352        off++;
     353    }
     354    pParsed->cchScheme = off;
     355
     356    /* Require the scheme length to be at least two chars so we won't confuse
     357       it with a path starting with a DOS drive letter specification. */
     358    if (RT_LIKELY(off >= 2)) { /* likely */ }
     359    else return VERR_URI_INVALID_SCHEME;
     360
     361    off++;                              /* (skip colon) */
     362
     363    /*
     364     * Find the end of the path, we'll need this several times.
     365     * Also, while we're potentially scanning the whole thing, check for '%'.
     366     */
     367    size_t const offHash         = RTStrOffCharOrTerm(&pszUri[off], '#') + off;
     368    size_t const offQuestionMark = RTStrOffCharOrTerm(&pszUri[off], '?') + off;
     369
     370    if (memchr(pszUri, '%', cchUri) != NULL)
     371        pParsed->fFlags |= RTURIPARSED_F_CONTAINS_ESCAPED_CHARS;
     372
     373    /*
     374     * RFC-3986, section 3.2:
     375     *      The authority component is preceeded by a double slash ("//")...
     376     */
     377    if (   pszUri[off] == '/'
     378        && pszUri[off + 1] == '/')
     379    {
     380        off += 2;
     381        pParsed->offAuthority = pParsed->offAuthorityUsername = pParsed->offAuthorityPassword = pParsed->offAuthorityHost = off;
     382        pParsed->fFlags |= RTURIPARSED_F_HAVE_AUTHORITY;
     383
     384        /*
     385         * RFC-3986, section 3.2:
     386         *      ...and is terminated by the next slash ("/"), question mark ("?"),
     387         *       or number sign ("#") character, or by the end of the URI.
     388         */
     389        const char *pszAuthority = &pszUri[off];
     390        size_t      cchAuthority = RTStrOffCharOrTerm(pszAuthority, '/');
     391        cchAuthority = RT_MIN(cchAuthority, offHash - off);
     392        cchAuthority = RT_MIN(cchAuthority, offQuestionMark - off);
     393        pParsed->cchAuthority     = cchAuthority;
     394
     395        /* The Authority can be empty, like for: file:///usr/bin/grep  */
     396        if (cchAuthority > 0)
     397        {
     398            pParsed->cchAuthorityHost = cchAuthority;
     399
     400            /*
     401             * If there is a userinfo part, it is ended by a '@'.
     402             */
     403            const char *pszAt = (const char *)memchr(pszAuthority, '@', cchAuthority);
     404            if (pszAt)
     405            {
     406                size_t cchTmp = pszAt - pszAuthority;
     407                pParsed->offAuthorityHost += cchTmp + 1;
     408                pParsed->cchAuthorityHost -= cchTmp + 1;
     409
     410                /* If there is a password part, it's separated from the username with a colon. */
     411                const char *pszColon = (const char *)memchr(pszAuthority, ':', cchTmp);
     412                if (pszColon)
     413                {
     414                    pParsed->cchAuthorityUsername = pszColon - pszAuthority;
     415                    pParsed->offAuthorityPassword = &pszColon[1] - pszUri;
     416                    pParsed->cchAuthorityPassword = pszAt - &pszColon[1];
     417                }
     418                else
     419                {
     420                    pParsed->cchAuthorityUsername = cchTmp;
     421                    pParsed->offAuthorityPassword = off + cchTmp;
     422                }
     423            }
     424
     425            /*
     426             * If there is a port part, its after the last colon in the host part.
     427             */
     428            const char *pszColon = (const char *)memrchr(&pszUri[pParsed->offAuthorityHost], ':', pParsed->cchAuthorityHost);
     429            if (pszColon)
     430            {
     431                size_t cchTmp = &pszUri[pParsed->offAuthorityHost + pParsed->cchAuthorityHost] - &pszColon[1];
     432                pParsed->cchAuthorityHost -= cchTmp + 1;
     433
     434                pParsed->uAuthorityPort = 0;
     435                while (cchTmp-- > 0)
     436                {
     437                    ch = *++pszColon;
     438                    if (   RT_C_IS_DIGIT(ch)
     439                        && pParsed->uAuthorityPort < UINT32_MAX / UINT32_C(10))
     440                    {
     441                        pParsed->uAuthorityPort *= 10;
     442                        pParsed->uAuthorityPort += ch - '0';
     443                    }
     444                    else
     445                        return VERR_URI_INVALID_PORT_NUMBER;
     446                }
     447            }
     448        }
     449
     450        /* Skip past the authority. */
     451        off += cchAuthority;
     452    }
     453    else
     454        pParsed->offAuthority = pParsed->offAuthorityUsername = pParsed->offAuthorityPassword = pParsed->offAuthorityHost = off;
     455
     456    /*
     457     * RFC-3986, section 3.3: Path
     458     *      The path is terminated by the first question mark ("?")
     459     *      or number sign ("#") character, or by the end of the URI.
     460     */
     461    pParsed->offPath = off;
     462    pParsed->cchPath = RT_MIN(offHash, offQuestionMark) - off;
     463    off += pParsed->cchPath;
     464
     465    /*
     466     * RFC-3986, section 3.4: Query
     467     *      The query component is indicated by the first question mark ("?")
     468     *      character and terminated by a number sign ("#") character or by the
     469     *      end of the URI.
     470     */
     471    if (   off == offQuestionMark
     472        && off < cchUri)
     473    {
     474        Assert(pszUri[offQuestionMark] == '?');
     475        pParsed->offQuery = ++off;
     476        pParsed->cchQuery = offHash - off;
     477        off = offHash;
     478    }
     479    else
     480    {
     481        Assert(!pszUri[offQuestionMark]);
     482        pParsed->offQuery = off;
     483    }
     484
     485    /*
     486     * RFC-3986, section 3.5: Fragment
     487     *      A fragment identifier component is indicated by the presence of a
     488     *      number sign ("#") character and terminated by the end of the URI.
     489     */
     490    if (   off == offHash
     491        && off < cchUri)
     492    {
     493        pParsed->offFragment = ++off;
     494        pParsed->cchFragment = cchUri - off;
     495    }
     496    else
     497    {
     498        Assert(!pszUri[offHash]);
     499        pParsed->offFragment = off;
     500    }
     501
     502    return VINF_SUCCESS;
    291503}
    292504
    293505
    294506/*********************************************************************************************************************************
    295 *   Public RTUri interface                                                                                                       *
     507*   Generic URI APIs                                                                                                             *
    296508*********************************************************************************************************************************/
    297509
    298 
    299 /*********************************************************************************************************************************
    300 *   Generic Uri methods                                                                                                          *
    301 *********************************************************************************************************************************/
    302 
    303 RTR3DECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery, const char *pszFragment)
     510RTR3DECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery,
     511                             const char *pszFragment)
    304512{
    305513    if (!pszScheme) /* Scheme is minimum requirement */
     
    346554        }
    347555
    348         char *pszTmp = pszResult = (char*)RTMemAllocZ(cbSize);
     556        char *pszTmp = pszResult = (char *)RTStrAlloc(cbSize);
    349557        if (!pszResult)
    350558            break;
     559        RT_BZERO(pszTmp, cbSize);
     560
    351561        /* Compose the target uri string. */
    352562        RTStrCatP(&pszTmp, &cbSize, pszScheme);
     
    371581            RTStrCatP(&pszTmp, &cbSize, pszFragment1);
    372582        }
    373     }while (0);
     583    } while (0);
    374584
    375585    /* Cleanup */
     
    411621RTR3DECL(char *) RTUriAuthority(const char *pszUri)
    412622{
     623    RTURIPARSED Parsed;
     624    int rc = rtUriParse(pszUri, &Parsed);
     625    if (RT_SUCCESS(rc))
     626        if (Parsed.cchAuthority || (Parsed.fFlags & RTURIPARSED_F_HAVE_AUTHORITY))
     627            return rtUriPercentDecodeN(&pszUri[Parsed.offAuthority], Parsed.cchAuthority);
     628    return NULL;
     629}
     630
     631RTR3DECL(char *) RTUriAuthorityUsername(const char *pszUri)
     632{
     633    RTURIPARSED Parsed;
     634    int rc = rtUriParse(pszUri, &Parsed);
     635    if (RT_SUCCESS(rc))
     636        if (Parsed.cchAuthorityUsername)
     637            return rtUriPercentDecodeN(&pszUri[Parsed.offAuthorityUsername], Parsed.cchAuthorityUsername);
     638    return NULL;
     639}
     640
     641RTR3DECL(char *) RTUriAuthorityPassword(const char *pszUri)
     642{
     643    RTURIPARSED Parsed;
     644    int rc = rtUriParse(pszUri, &Parsed);
     645    if (RT_SUCCESS(rc))
     646        if (Parsed.cchAuthorityPassword)
     647            return rtUriPercentDecodeN(&pszUri[Parsed.offAuthorityPassword], Parsed.cchAuthorityPassword);
     648    return NULL;
     649}
     650
     651RTR3DECL(uint32_t) RTUriAuthorityPort(const char *pszUri)
     652{
     653    RTURIPARSED Parsed;
     654    int rc = rtUriParse(pszUri, &Parsed);
     655    if (RT_SUCCESS(rc))
     656        return Parsed.uAuthorityPort;
     657    return UINT32_MAX;
     658}
     659
     660RTR3DECL(char *) RTUriPath(const char *pszUri)
     661{
     662    RTURIPARSED Parsed;
     663    int rc = rtUriParse(pszUri, &Parsed);
     664    if (RT_SUCCESS(rc))
     665        if (Parsed.cchPath)
     666            return rtUriPercentDecodeN(&pszUri[Parsed.offPath], Parsed.cchPath);
     667    return NULL;
     668}
     669
     670RTR3DECL(char *) RTUriQuery(const char *pszUri)
     671{
     672    RTURIPARSED Parsed;
     673    int rc = rtUriParse(pszUri, &Parsed);
     674    if (RT_SUCCESS(rc))
     675        if (Parsed.cchQuery)
     676            return rtUriPercentDecodeN(&pszUri[Parsed.offQuery], Parsed.cchQuery);
     677    return NULL;
     678}
     679
     680RTR3DECL(char *) RTUriFragment(const char *pszUri)
     681{
     682    RTURIPARSED Parsed;
     683    int rc = rtUriParse(pszUri, &Parsed);
     684    if (RT_SUCCESS(rc))
     685        if (Parsed.cchFragment)
     686            return rtUriPercentDecodeN(&pszUri[Parsed.offFragment], Parsed.cchFragment);
     687    return NULL;
     688}
     689
     690
     691/*********************************************************************************************************************************
     692*   File URI APIs                                                                                                                *
     693*********************************************************************************************************************************/
     694
     695RTR3DECL(char *) RTUriFileCreate(const char *pszPath)
     696{
     697    char *pszResult = NULL;
     698    if (pszPath)
     699    {
     700        /* Create the percent encoded strings and calculate the necessary uri length. */
     701        char *pszPath1 = rtUriPercentEncodeN(pszPath, RTSTR_MAX);
     702        if (pszPath1)
     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    return pszResult;
     721}
     722
     723RTR3DECL(char *) RTUriFilePath(const char *pszUri, uint32_t uFormat)
     724{
     725    return RTUriFileNPath(pszUri, uFormat, RTSTR_MAX);
     726}
     727
     728RTR3DECL(char *) RTUriFileNPath(const char *pszUri, uint32_t uFormat, size_t cchMax)
     729{
    413730    AssertPtrReturn(pszUri, NULL);
    414 
    415     size_t iPos1;
    416     size_t cbLen = strlen(pszUri);
    417     /* Find the end of the scheme. */
    418     if (!rtUriFindSchemeEnd(pszUri, 0, cbLen, &iPos1))
    419         return NULL; /* no URI */
    420     else
    421         ++iPos1; /* Skip ':' */
    422 
    423     size_t iPos2;
    424     /* Find the start of the authority. */
    425     if (rtUriCheckAuthorityStart(pszUri, iPos1, cbLen - iPos1, &iPos2))
    426     {
    427         size_t iPos3 = cbLen;
    428         /* Find the end of the authority. If not found, the rest of the string
    429          * is used. */
    430         rtUriFindAuthorityEnd(pszUri, iPos2, cbLen - iPos2, &iPos3);
    431         if (iPos3 > iPos2) /* Length check */
    432             return rtUriPercentDecodeN(&pszUri[iPos2], iPos3 - iPos2);
    433         else
    434             return NULL;
     731    AssertReturn(uFormat == URI_FILE_FORMAT_AUTO || uFormat == URI_FILE_FORMAT_UNIX || uFormat == URI_FILE_FORMAT_WIN, NULL);
     732
     733    /* Auto is based on the current OS. */
     734    if (uFormat == URI_FILE_FORMAT_AUTO)
     735#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     736        uFormat = URI_FILE_FORMAT_WIN;
     737#else
     738        uFormat = URI_FILE_FORMAT_UNIX;
     739#endif
     740
     741    /* Check that this is a file Uri */
     742    if (RTStrNICmp(pszUri, RT_STR_TUPLE("file:")) != 0)
     743        return NULL;
     744
     745    RTURIPARSED Parsed;
     746    int rc = rtUriParse(pszUri, &Parsed);
     747    if (RT_SUCCESS(rc) && Parsed.cchPath)
     748    {
     749        /* Special hack for DOS path like file:///c:/WINDOWS/clock.avi where we
     750           have to drop the leading slash that was used to separate the authority
     751           from the path. */
     752        if (  uFormat == URI_FILE_FORMAT_WIN
     753            && Parsed.cchPath >= 3
     754            && pszUri[Parsed.offPath] == '/'
     755            && pszUri[Parsed.offPath + 2] == ':'
     756            && RT_C_IS_ALPHA(pszUri[Parsed.offPath + 1]) )
     757        {
     758            Parsed.offPath++;
     759            Parsed.cchPath--;
     760        }
     761
     762        char *pszPath = rtUriPercentDecodeN(&pszUri[Parsed.offPath], Parsed.cchPath);
     763        if (uFormat == URI_FILE_FORMAT_UNIX)
     764            return RTPathChangeToUnixSlashes(pszPath, true);
     765        Assert(uFormat == URI_FILE_FORMAT_WIN);
     766        return RTPathChangeToDosSlashes(pszPath, true);
    435767    }
    436768    return NULL;
    437769}
    438770
    439 RTR3DECL(char *) RTUriPath(const char *pszUri)
    440 {
    441     AssertPtrReturn(pszUri, NULL);
    442 
    443     size_t iPos1;
    444     size_t cbLen = strlen(pszUri);
    445     /* Find the end of the scheme. */
    446     if (!rtUriFindSchemeEnd(pszUri, 0, cbLen, &iPos1))
    447         return NULL; /* no URI */
    448     else
    449         ++iPos1; /* Skip ':' */
    450 
    451     size_t iPos2;
    452     size_t iPos3 = iPos1; /* Skip if no authority is found */
    453     /* Find the start of the authority. */
    454     if (rtUriCheckAuthorityStart(pszUri, iPos1, cbLen - iPos1, &iPos2))
    455     {
    456         /* Find the end of the authority. If not found, then there is no path
    457          * component, cause the authority is the rest of the string. */
    458         if (!rtUriFindAuthorityEnd(pszUri, iPos2, cbLen - iPos2, &iPos3))
    459             return NULL; /* no path! */
    460     }
    461 
    462     size_t iPos4;
    463     /* Find the start of the path */
    464     if (rtUriCheckPathStart(pszUri, iPos3, cbLen - iPos3, &iPos4))
    465     {
    466         /* Search for the end of the scheme. */
    467         size_t iPos5 = cbLen;
    468         rtUriFindPathEnd(pszUri, iPos4, cbLen - iPos4, &iPos5);
    469         if (iPos5 > iPos4) /* Length check */
    470             return rtUriPercentDecodeN(&pszUri[iPos4], iPos5 - iPos4);
    471     }
    472 
    473     return NULL;
    474 }
    475 
    476 RTR3DECL(char *) RTUriQuery(const char *pszUri)
    477 {
    478     AssertPtrReturn(pszUri, NULL);
    479 
    480     size_t iPos1;
    481     size_t cbLen = strlen(pszUri);
    482     /* Find the end of the scheme. */
    483     if (!rtUriFindSchemeEnd(pszUri, 0, cbLen, &iPos1))
    484         return NULL; /* no URI */
    485     else
    486         ++iPos1; /* Skip ':' */
    487 
    488     size_t iPos2;
    489     size_t iPos3 = iPos1; /* Skip if no authority is found */
    490     /* Find the start of the authority. */
    491     if (rtUriCheckAuthorityStart(pszUri, iPos1, cbLen - iPos1, &iPos2))
    492     {
    493         /* Find the end of the authority. If not found, then there is no path
    494          * component, cause the authority is the rest of the string. */
    495         if (!rtUriFindAuthorityEnd(pszUri, iPos2, cbLen - iPos2, &iPos3))
    496             return NULL; /* no path! */
    497     }
    498 
    499     size_t iPos4;
    500     size_t iPos5 = iPos3; /* Skip if no path is found */
    501     /* Find the start of the path */
    502     if (rtUriCheckPathStart(pszUri, iPos3, cbLen - iPos3, &iPos4))
    503     {
    504         /* Find the end of the path. If not found, then there is no query
    505          * component, cause the path is the rest of the string. */
    506         if (!rtUriFindPathEnd(pszUri, iPos4, cbLen - iPos4, &iPos5))
    507             return NULL; /* no query! */
    508     }
    509 
    510     size_t iPos6;
    511     /* Find the start of the query */
    512     if (rtUriCheckQueryStart(pszUri, iPos5, cbLen - iPos5, &iPos6))
    513     {
    514         /* Search for the end of the query. */
    515         size_t iPos7 = cbLen;
    516         rtUriFindQueryEnd(pszUri, iPos6, cbLen - iPos6, &iPos7);
    517         if (iPos7 > iPos6) /* Length check */
    518             return rtUriPercentDecodeN(&pszUri[iPos6], iPos7 - iPos6);
    519     }
    520 
    521     return NULL;
    522 }
    523 
    524 RTR3DECL(char *) RTUriFragment(const char *pszUri)
    525 {
    526     AssertPtrReturn(pszUri, NULL);
    527 
    528     size_t iPos1;
    529     size_t cbLen = strlen(pszUri);
    530     /* Find the end of the scheme. */
    531     if (!rtUriFindSchemeEnd(pszUri, 0, cbLen, &iPos1))
    532         return NULL; /* no URI */
    533     else
    534         ++iPos1; /* Skip ':' */
    535 
    536     size_t iPos2;
    537     size_t iPos3 = iPos1; /* Skip if no authority is found */
    538     /* Find the start of the authority. */
    539     if (rtUriCheckAuthorityStart(pszUri, iPos1, cbLen - iPos1, &iPos2))
    540     {
    541         /* Find the end of the authority. If not found, then there is no path
    542          * component, cause the authority is the rest of the string. */
    543         if (!rtUriFindAuthorityEnd(pszUri, iPos2, cbLen - iPos2, &iPos3))
    544             return NULL; /* no path! */
    545     }
    546 
    547     size_t iPos4;
    548     size_t iPos5 = iPos3; /* Skip if no path is found */
    549     /* Find the start of the path */
    550     if (rtUriCheckPathStart(pszUri, iPos3, cbLen - iPos3, &iPos4))
    551     {
    552         /* Find the end of the path. If not found, then there is no query
    553          * component, cause the path is the rest of the string. */
    554         if (!rtUriFindPathEnd(pszUri, iPos4, cbLen - iPos4, &iPos5))
    555             return NULL; /* no query! */
    556     }
    557 
    558     size_t iPos6;
    559     size_t iPos7 = iPos5; /* Skip if no query is found */
    560     /* Find the start of the query */
    561     if (rtUriCheckQueryStart(pszUri, iPos5, cbLen - iPos5, &iPos6))
    562     {
    563         /* Find the end of the query If not found, then there is no fragment
    564          * component, cause the query is the rest of the string. */
    565         if (!rtUriFindQueryEnd(pszUri, iPos6, cbLen - iPos6, &iPos7))
    566             return NULL; /* no query! */
    567     }
    568 
    569 
    570     size_t iPos8;
    571     /* Find the start of the fragment */
    572     if (rtUriCheckFragmentStart(pszUri, iPos7, cbLen - iPos7, &iPos8))
    573     {
    574         /* There could be nothing behind a fragment. So use the rest of the
    575          * string. */
    576         if (cbLen > iPos8) /* Length check */
    577             return rtUriPercentDecodeN(&pszUri[iPos8], cbLen - iPos8);
    578     }
    579     return NULL;
    580 }
    581 
    582 
    583 /*********************************************************************************************************************************
    584 *   File Uri methods                                                                                                             *
    585 *********************************************************************************************************************************/
    586 
    587 RTR3DECL(char *) RTUriFileCreate(const char *pszPath)
    588 {
    589     if (!pszPath)
    590         return NULL;
    591 
    592     char *pszResult = 0;
    593     char *pszPath1 = 0;
    594 
    595     do
    596     {
    597         /* Create the percent encoded strings and calculate the necessary uri
    598          * length. */
    599         pszPath1 = rtUriPercentEncodeN(pszPath, RTSTR_MAX);
    600         if (!pszPath1)
    601             break;
    602         size_t cbSize = 7 /* file:// */ + strlen(pszPath1) + 1; /* plus zero byte */
    603         if (pszPath1[0] != '/')
    604             ++cbSize;
    605         char *pszTmp = pszResult = (char*)RTMemAllocZ(cbSize);
    606         if (!pszResult)
    607             break;
    608         /* Compose the target uri string. */
    609         RTStrCatP(&pszTmp, &cbSize, "file://");
    610         if (pszPath1[0] != '/')
    611             RTStrCatP(&pszTmp, &cbSize, "/");
    612         RTStrCatP(&pszTmp, &cbSize, pszPath1);
    613     }while (0);
    614 
    615     /* Cleanup */
    616     if (pszPath1)
    617         RTStrFree(pszPath1);
    618 
    619     return pszResult;
    620 }
    621 
    622 RTR3DECL(char *) RTUriFilePath(const char *pszUri, uint32_t uFormat)
    623 {
    624     return RTUriFileNPath(pszUri, uFormat, RTSTR_MAX);
    625 }
    626 
    627 RTR3DECL(char *) RTUriFileNPath(const char *pszUri, uint32_t uFormat, size_t cchMax)
    628 {
    629     AssertPtrReturn(pszUri, NULL);
    630 
    631     size_t iPos1;
    632     size_t cbLen = RT_MIN(strlen(pszUri), cchMax);
    633     /* Find the end of the scheme. */
    634     if (!rtUriFindSchemeEnd(pszUri, 0, cbLen, &iPos1))
    635         return NULL; /* no URI */
    636     else
    637         ++iPos1; /* Skip ':' */
    638 
    639     /* Check that this is a file Uri */
    640     if (RTStrNICmp(pszUri, "file:", iPos1) != 0)
    641         return NULL;
    642 
    643     size_t iPos2;
    644     size_t iPos3 = iPos1; /* Skip if no authority is found */
    645     /* Find the start of the authority. */
    646     if (rtUriCheckAuthorityStart(pszUri, iPos1, cbLen - iPos1, &iPos2))
    647     {
    648         /* Find the end of the authority. If not found, then there is no path
    649          * component, cause the authority is the rest of the string. */
    650         if (!rtUriFindAuthorityEnd(pszUri, iPos2, cbLen - iPos2, &iPos3))
    651             return NULL; /* no path! */
    652     }
    653 
    654     size_t iPos4;
    655     /* Find the start of the path */
    656     if (rtUriCheckPathStart(pszUri, iPos3, cbLen - iPos3, &iPos4))
    657     {
    658         uint32_t uFIntern = uFormat;
    659         /* Auto is based on the current OS. */
    660         if (uFormat == URI_FILE_FORMAT_AUTO)
    661 #ifdef RT_OS_WINDOWS
    662             uFIntern = URI_FILE_FORMAT_WIN;
    663 #else /* RT_OS_WINDOWS */
    664             uFIntern = URI_FILE_FORMAT_UNIX;
    665 #endif /* !RT_OS_WINDOWS */
    666 
    667         if (   uFIntern != URI_FILE_FORMAT_UNIX
    668             && pszUri[iPos4] == '/')
    669             ++iPos4;
    670         /* Search for the end of the scheme. */
    671         size_t iPos5 = cbLen;
    672         rtUriFindPathEnd(pszUri, iPos4, cbLen - iPos4, &iPos5);
    673         if (iPos5 > iPos4) /* Length check */
    674         {
    675             char *pszPath = rtUriPercentDecodeN(&pszUri[iPos4], iPos5 - iPos4);
    676             if (uFIntern == URI_FILE_FORMAT_UNIX)
    677                 return RTPathChangeToUnixSlashes(pszPath, true);
    678             else if (uFIntern == URI_FILE_FORMAT_WIN)
    679                 return RTPathChangeToDosSlashes(pszPath, true);
    680             else
    681             {
    682                 RTStrFree(pszPath);
    683                 AssertMsgFailed(("Unknown uri file format %u", uFIntern));
    684                 return NULL;
    685             }
    686         }
    687     }
    688 
    689     return NULL;
    690 }
    691 
Note: See TracChangeset for help on using the changeset viewer.

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