VirtualBox

Changeset 57723 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Sep 11, 2015 8:02:15 PM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
102638
Message:

RTUri: Reworked the API to a one time parsing and make sure we get UTF-8 clean strings from it.

Location:
trunk/src/VBox/Runtime
Files:
2 edited

Legend:

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

    r57720 r57723  
    3636#include <iprt/string.h>
    3737
     38
     39/*********************************************************************************************************************************
     40*   Defined Constants And Macros                                                                                                 *
     41*********************************************************************************************************************************/
     42/** Internal magic value we use to check if a RTURIPARSED structure has made it thru RTUriParse. */
     43#define RTURIPARSED_MAGIC   UINT32_C(0x439e0745)
     44
     45
    3846/* General URI format:
    3947
     
    4755*/
    4856
    49 /**
    50  * Parsed URI.
    51  */
    52 typedef 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. */
    103 typedef 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 
    111 
    112 /*********************************************************************************************************************************
    113 *   Internal Functions                                                                                                           *
    114 *********************************************************************************************************************************/
    11557
    11658/**
     
    176118}
    177119
    178 static char *rtUriPercentDecodeN(const char *pszString, size_t cchMax)
    179 {
    180     if (!pszString)
    181         return NULL;
    182 
    183     /* The new string can only get smaller. */
    184     size_t cchLen = strlen(pszString);
    185     cchLen = RT_MIN(cchLen, cchMax);
    186     char *pszNew = RTStrAlloc(cchLen + 1);
    187     if (!pszNew)
    188         return NULL;
    189 
    190     int rc = VINF_SUCCESS;
    191     char *pszRes = NULL;
    192     size_t iIn = 0;
    193     size_t iOut = 0;
    194     while (iIn < cchLen)
    195     {
    196         if (pszString[iIn] == '%')
    197         {
    198             /* % encoding means the percent sign and exactly 2 hexadecimal
    199              * digits describing the ASCII number of the character. */
    200             ++iIn;
    201             char szNum[3];
    202             szNum[0] = pszString[iIn++];
    203             szNum[1] = pszString[iIn++];
    204             szNum[2] = '\0';
    205 
    206             uint8_t u8;
    207             rc = RTStrToUInt8Ex(szNum, NULL, 16, &u8);
    208             if (RT_FAILURE(rc))
     120
     121static char *rtUriPercentDecodeN(const char *pszString, size_t cchString)
     122{
     123    AssertPtr(pszString);
     124    Assert(strlen(pszString) >= cchString);
     125
     126    /*
     127     * The new string can only get smaller, so use the input length as a
     128     * staring buffer size.
     129     */
     130    char *pszDecoded = RTStrAlloc(cchString + 1);
     131    if (pszDecoded)
     132    {
     133        /*
     134         * Knowing that the pszString itself is valid UTF-8, we only have to
     135         * validate the escape sequences.
     136         */
     137        size_t      cchLeft = cchString;
     138        char const *pchSrc  = pszString;
     139        char       *pchDst  = pszDecoded;
     140        while (cchLeft > 0)
     141        {
     142            const char *pchPct = (const char *)memchr(pchSrc, '%', cchLeft);
     143            if (pchPct)
     144            {
     145                size_t cchBefore = pchPct - pchSrc;
     146                if (cchBefore)
     147                {
     148                    memcpy(pchDst, pchSrc, cchBefore);
     149                    pchDst  += cchBefore;
     150                    pchSrc  += cchBefore;
     151                    cchLeft -= cchBefore;
     152                }
     153
     154                char chHigh, chLow;
     155                if (   cchLeft >= 3
     156                    && RT_C_IS_XDIGIT(chHigh = pchSrc[1])
     157                    && RT_C_IS_XDIGIT(chLow  = pchSrc[2]))
     158                {
     159                    uint8_t b = RT_C_IS_DIGIT(chHigh) ? chHigh - '0' : (chHigh & ~0x20) - 'A' + 10;
     160                    b <<= 4;
     161                    b |= RT_C_IS_DIGIT(chLow) ? chLow - '0' : (chLow & ~0x20) - 'A' + 10;
     162                    *pchDst++ = (char)b;
     163                    pchSrc  += 3;
     164                    cchLeft -= 3;
     165                }
     166                else
     167                {
     168                    AssertFailed();
     169                    *pchDst++ = *pchSrc++;
     170                    cchLeft--;
     171                }
     172            }
     173            else
     174            {
     175                memcpy(pchDst, pchSrc, cchLeft);
     176                pchDst += cchLeft;
     177                pchSrc += cchLeft;
     178                cchLeft = 0;
    209179                break;
    210             pszNew[iOut] = u8;
    211         }
    212         else
    213             pszNew[iOut] = pszString[iIn++];
    214         ++iOut;
    215     }
    216     if (RT_SUCCESS(rc))
    217     {
    218         pszNew[iOut] = '\0';
    219         if (iOut != iIn)
    220         {
    221             /* If the source and target strings have different size, recreate
    222              * the target string with the correct size. */
    223             pszRes = RTStrDupN(pszNew, iOut);
    224             RTStrFree(pszNew);
    225         }
    226         else
    227             pszRes = pszNew;
    228     }
    229     else
    230         RTStrFree(pszNew);
    231 
    232     return pszRes;
    233 }
    234 
    235 static bool rtUriFindSchemeEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
    236 {
    237     /* The scheme has to end with ':'. */
    238     size_t i = iStart;
    239     while (i < iStart + cbLen)
    240     {
    241         if (pszUri[i] == ':')
    242         {
    243             *piEnd = i;
    244             return true;
    245         }
    246         ++i;
    247     }
    248     return false;
    249 }
    250 
    251 static bool rtUriCheckAuthorityStart(const char *pszUri, size_t iStart, size_t cbLen, size_t *piStart)
    252 {
    253     /* The authority have to start with '//' */
    254     if (   cbLen >= 2
    255         && pszUri[iStart    ] == '/'
    256         && pszUri[iStart + 1] == '/')
    257     {
    258         *piStart = iStart + 2;
    259         return true;
    260     }
    261 
    262     return false;
    263 }
    264 
    265 static bool rtUriFindAuthorityEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
    266 {
    267     /* The authority can end with '/' || '?' || '#'. */
    268     size_t i = iStart;
    269     while (i < iStart + cbLen)
    270     {
    271         if (   pszUri[i] == '/'
    272             || pszUri[i] == '?'
    273             || pszUri[i] == '#')
    274         {
    275             *piEnd = i;
    276             return true;
    277         }
    278         ++i;
    279     }
    280     return false;
    281 }
    282 
    283 static bool rtUriCheckPathStart(const char *pszUri, size_t iStart, size_t cbLen, size_t *piStart)
    284 {
    285     /* The path could start with a '/'. */
    286     if (   cbLen >= 1
    287         && pszUri[iStart] == '/')
    288     {
    289         *piStart = iStart; /* Including '/' */
    290         return true;
    291     }
    292 
    293     /* '?' || '#' means there is no path. */
    294     if (   cbLen >= 1
    295         && (   pszUri[iStart] == '?'
    296             || pszUri[iStart] == '#'))
    297         return false;
    298 
    299     /* All other values are allowed. */
    300     *piStart = iStart;
    301     return true;
    302 }
    303 
    304 static bool rtUriFindPathEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
    305 {
    306     /* The path can end with '?' || '#'. */
    307     size_t i = iStart;
    308     while (i < iStart + cbLen)
    309     {
    310         if (   pszUri[i] == '?'
    311             || pszUri[i] == '#')
    312         {
    313             *piEnd = i;
    314             return true;
    315         }
    316         ++i;
    317     }
    318     return false;
    319 }
     180            }
     181        }
     182
     183        *pchDst = '\0';
     184
     185        /*
     186         * If we've got lof space room in the result string, reallocate it.
     187         */
     188        size_t cchDecoded = pchDst - pszDecoded;
     189        Assert(cchDecoded <= cchString);
     190        // if (cchString - cchDecoded > 64)  -  enable later!
     191            RTStrRealloc(&pszDecoded, cchDecoded + 1);
     192    }
     193    return pszDecoded;
     194}
     195
    320196
    321197static int rtUriParse(const char *pszUri, PRTURIPARSED pParsed)
     
    329205
    330206    AssertPtrReturn(pszUri, VERR_INVALID_POINTER);
     207
    331208    size_t const cchUri = strlen(pszUri);
    332209    if (RT_LIKELY(cchUri >= 3)) { /* likely */ }
    333210    else return cchUri ? VERR_URI_TOO_SHORT : VERR_URI_EMPTY;
     211
     212    /*
     213     * Validating escaped text sequences is much simpler if we know that
     214     * that the base URI string is valid.  Also, we don't necessarily trust
     215     * the developer calling us to remember to do this.
     216     */
     217    int rc = RTStrValidateEncoding(pszUri);
     218    AssertRCReturn(rc, rc);
    334219
    335220    /*
     
    500385    }
    501386
     387    /*
     388     * If there are any escape sequences, validate them.
     389     *
     390     * This is reasonably simple as we already know that the string is valid UTF-8
     391     * before they get decoded.  Thus we only have to validate the escaped sequences.
     392     */
     393    if (pParsed->fFlags & RTURIPARSED_F_CONTAINS_ESCAPED_CHARS)
     394    {
     395        const char *pchSrc  = (const char *)memchr(pszUri, '%', cchUri);
     396        AssertReturn(pchSrc, VERR_INTERNAL_ERROR);
     397        do
     398        {
     399            char        szUtf8Seq[8];
     400            unsigned    cchUtf8Seq = 0;
     401            unsigned    cchNeeded  = 0;
     402            size_t      cchLeft    = &pszUri[cchUri] - pchSrc;
     403            do
     404            {
     405                if (cchLeft >= 3)
     406                {
     407                    char chHigh = pchSrc[1];
     408                    char chLow  = pchSrc[2];
     409                    if (   RT_C_IS_XDIGIT(chHigh)
     410                        && RT_C_IS_XDIGIT(chLow))
     411                    {
     412                        uint8_t b = RT_C_IS_DIGIT(chHigh) ? chHigh - '0' : (chHigh & ~0x20) - 'A' + 10;
     413                        b <<= 4;
     414                        b |= RT_C_IS_DIGIT(chLow) ? chLow - '0' : (chLow & ~0x20) - 'A' + 10;
     415
     416                        if (!(b & 0x80))
     417                        {
     418                            /* We don't want the string to be terminated prematurely. */
     419                            if (RT_LIKELY(b != 0)) { /* likely */ }
     420                            else return VERR_URI_ESCAPED_ZERO;
     421
     422                            /* Check that we're not expecting more UTF-8 bytes. */
     423                            if (RT_LIKELY(cchNeeded == 0)) { /* likely */ }
     424                            else return VERR_URI_MISSING_UTF8_CONTINUATION_BYTE;
     425                        }
     426                        /* Are we waiting UTF-8 bytes? */
     427                        else if (cchNeeded > 0)
     428                        {
     429                            if (RT_LIKELY(!(b & 0x40))) { /* likely */ }
     430                            else return VERR_URI_INVALID_ESCAPED_UTF8_CONTINUATION_BYTE;
     431
     432                            szUtf8Seq[cchUtf8Seq++] = (char)b;
     433                            if (--cchNeeded == 0)
     434                            {
     435                                szUtf8Seq[cchUtf8Seq] = '\0';
     436                                int rc = RTStrValidateEncoding(szUtf8Seq);
     437                                if (RT_FAILURE(rc))
     438                                    return VERR_URI_ESCAPED_CHARS_NOT_VALID_UTF8;
     439                                cchUtf8Seq = 0;
     440                            }
     441                        }
     442                        /* Start a new UTF-8 sequence. */
     443                        else
     444                        {
     445                            if ((b & 0xf8) == 0xf0)
     446                                cchNeeded = 3;
     447                            else if ((b & 0xf0) == 0xe0)
     448                                cchNeeded = 2;
     449                            else if ((b & 0xe0) == 0xc0)
     450                                cchNeeded = 1;
     451                            else
     452                                return VERR_URI_INVALID_ESCAPED_UTF8_LEAD_BYTE;
     453                            szUtf8Seq[0] = (char)b;
     454                            cchUtf8Seq = 1;
     455                        }
     456                        pchSrc  += 3;
     457                        cchLeft -= 3;
     458                    }
     459                    else
     460                        return VERR_URI_INVALID_ESCAPE_SEQ;
     461                }
     462                else
     463                    return VERR_URI_INVALID_ESCAPE_SEQ;
     464            } while (cchLeft > 0 && pchSrc[0] == '%');
     465
     466            /* Check that we're not expecting more UTF-8 bytes. */
     467            if (RT_LIKELY(cchNeeded == 0)) { /* likely */ }
     468            else return VERR_URI_MISSING_UTF8_CONTINUATION_BYTE;
     469
     470            /* next */
     471            pchSrc = (const char *)memchr(pchSrc, '%', cchLeft);
     472        } while (pchSrc);
     473    }
     474
     475    pParsed->u32Magic = RTURIPARSED_MAGIC;
    502476    return VINF_SUCCESS;
    503477}
    504478
    505479
    506 /*********************************************************************************************************************************
    507 *   Generic URI APIs                                                                                                             *
    508 *********************************************************************************************************************************/
    509 
    510 RTR3DECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery,
    511                              const char *pszFragment)
     480
     481RTDECL(int) RTUriParse(const char *pszUri, PRTURIPARSED pParsed)
     482{
     483    return rtUriParse(pszUri, pParsed);
     484}
     485
     486
     487RTDECL(char *) RTUriParsedScheme(const char *pszUri, PCRTURIPARSED pParsed)
     488{
     489    AssertPtrReturn(pszUri, NULL);
     490    AssertPtrReturn(pParsed, NULL);
     491    AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
     492    return RTStrDupN(pszUri, pParsed->cchScheme);
     493}
     494
     495
     496RTDECL(char *) RTUriParsedAuthority(const char *pszUri, PCRTURIPARSED pParsed)
     497{
     498    AssertPtrReturn(pszUri, NULL);
     499    AssertPtrReturn(pParsed, NULL);
     500    AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
     501    if (pParsed->cchAuthority || (pParsed->fFlags & RTURIPARSED_F_HAVE_AUTHORITY))
     502        return rtUriPercentDecodeN(&pszUri[pParsed->offAuthority], pParsed->cchAuthority);
     503    return NULL;
     504}
     505
     506
     507RTDECL(char *) RTUriParsedAuthorityUsername(const char *pszUri, PCRTURIPARSED pParsed)
     508{
     509    AssertPtrReturn(pszUri, NULL);
     510    AssertPtrReturn(pParsed, NULL);
     511    AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
     512    if (pParsed->cchAuthorityUsername)
     513        return rtUriPercentDecodeN(&pszUri[pParsed->offAuthorityUsername], pParsed->cchAuthorityUsername);
     514    return NULL;
     515}
     516
     517
     518RTDECL(char *) RTUriParsedAuthorityPassword(const char *pszUri, PCRTURIPARSED pParsed)
     519{
     520    AssertPtrReturn(pszUri, NULL);
     521    AssertPtrReturn(pParsed, NULL);
     522    AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
     523    if (pParsed->cchAuthorityPassword)
     524        return rtUriPercentDecodeN(&pszUri[pParsed->offAuthorityPassword], pParsed->cchAuthorityPassword);
     525    return NULL;
     526}
     527
     528
     529RTDECL(char *) RTUriParsedAuthorityHost(const char *pszUri, PCRTURIPARSED pParsed)
     530{
     531    AssertPtrReturn(pszUri, NULL);
     532    AssertPtrReturn(pParsed, NULL);
     533    AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
     534    if (pParsed->cchAuthorityHost)
     535        return rtUriPercentDecodeN(&pszUri[pParsed->offAuthorityHost], pParsed->cchAuthorityHost);
     536    return NULL;
     537}
     538
     539
     540RTDECL(uint32_t) RTUriParsedAuthorityPort(const char *pszUri, PCRTURIPARSED pParsed)
     541{
     542    AssertPtrReturn(pszUri, UINT32_MAX);
     543    AssertPtrReturn(pParsed, UINT32_MAX);
     544    AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, UINT32_MAX);
     545    return pParsed->uAuthorityPort;
     546}
     547
     548
     549RTDECL(char *) RTUriParsedPath(const char *pszUri, PCRTURIPARSED pParsed)
     550{
     551    AssertPtrReturn(pszUri, NULL);
     552    AssertPtrReturn(pParsed, NULL);
     553    AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
     554    if (pParsed->cchPath)
     555        return rtUriPercentDecodeN(&pszUri[pParsed->offPath], pParsed->cchPath);
     556    return NULL;
     557}
     558
     559
     560RTDECL(char *) RTUriParsedQuery(const char *pszUri, PCRTURIPARSED pParsed)
     561{
     562    AssertPtrReturn(pszUri, NULL);
     563    AssertPtrReturn(pParsed, NULL);
     564    AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
     565    if (pParsed->cchQuery)
     566        return rtUriPercentDecodeN(&pszUri[pParsed->offQuery], pParsed->cchQuery);
     567    return NULL;
     568}
     569
     570
     571RTDECL(char *) RTUriParsedFragment(const char *pszUri, PCRTURIPARSED pParsed)
     572{
     573    AssertPtrReturn(pszUri, NULL);
     574    AssertPtrReturn(pParsed, NULL);
     575    AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
     576    if (pParsed->cchFragment)
     577        return rtUriPercentDecodeN(&pszUri[pParsed->offFragment], pParsed->cchFragment);
     578    return NULL;
     579}
     580
     581
     582RTDECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery,
     583                           const char *pszFragment)
    512584{
    513585    if (!pszScheme) /* Scheme is minimum requirement */
     
    596668}
    597669
    598 RTR3DECL(bool)   RTUriHasScheme(const char *pszUri, const char *pszScheme)
    599 {
    600     bool fRes = false;
    601     char *pszTmp = RTUriScheme(pszUri);
    602     if (pszTmp)
    603     {
    604         fRes = RTStrNICmp(pszScheme, pszTmp, strlen(pszTmp)) == 0;
    605         RTStrFree(pszTmp);
    606     }
    607     return fRes;
    608 }
    609 
    610 RTR3DECL(char *) RTUriScheme(const char *pszUri)
    611 {
    612     AssertPtrReturn(pszUri, NULL);
    613 
    614     size_t iPos1;
    615     size_t cbLen = strlen(pszUri);
    616     if (rtUriFindSchemeEnd(pszUri, 0, cbLen, &iPos1))
    617         return rtUriPercentDecodeN(pszUri, iPos1);
    618     return NULL;
    619 }
    620 
    621 RTR3DECL(char *) RTUriAuthority(const char *pszUri)
    622 {
    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 
    631 RTR3DECL(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 
    641 RTR3DECL(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 
    651 RTR3DECL(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 
    660 RTR3DECL(char *) RTUriPath(const char *pszUri)
     670
     671RTDECL(bool)   RTUriIsSchemeMatch(const char *pszUri, const char *pszScheme)
     672{
     673    AssertPtrReturn(pszUri, false);
     674    size_t const cchScheme = strlen(pszScheme);
     675    return RTStrNICmp(pszUri, pszScheme, cchScheme) == 0
     676        && pszScheme[cchScheme] == ':';
     677}
     678
     679
     680/* temporarily kept around till Andy stops using it. */
     681RTDECL(char *) RTUriPath(const char *pszUri)
    661682{
    662683    RTURIPARSED Parsed;
     
    668689}
    669690
    670 RTR3DECL(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 
    680 RTR3DECL(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 
    695 RTR3DECL(char *) RTUriFileCreate(const char *pszPath)
     691
     692RTDECL(char *) RTUriFileCreate(const char *pszPath)
    696693{
    697694    char *pszResult = NULL;
     
    721718}
    722719
    723 RTR3DECL(char *) RTUriFilePath(const char *pszUri, uint32_t uFormat)
     720
     721RTDECL(char *) RTUriFilePath(const char *pszUri, uint32_t uFormat)
    724722{
    725723    return RTUriFileNPath(pszUri, uFormat, RTSTR_MAX);
    726724}
    727725
    728 RTR3DECL(char *) RTUriFileNPath(const char *pszUri, uint32_t uFormat, size_t cchMax)
     726
     727RTDECL(char *) RTUriFileNPath(const char *pszUri, uint32_t uFormat, size_t cchMax)
    729728{
    730729    AssertPtrReturn(pszUri, NULL);
  • trunk/src/VBox/Runtime/testcase/tstRTUri.cpp

    r57720 r57723  
    5252    const char *pszUsername;
    5353    const char *pszPassword;
     54    const char *pszHost;
    5455    uint32_t    uPort;
    5556} g_aTests[] =
    5657{
    5758    {   /* #0 */
    58         "foo://tt:[email protected]:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
    59         /*.pszScheme    =*/ "foo",
    60         /*.pszAuthority =*/ "tt:[email protected]:8042",
    61         /*.pszPath      =*/ "/over/ <>#%\"{}|^[]`/there",
    62         /*.pszQuery     =*/ "name= <>#%\"{}|^[]`ferret",
    63         /*.pszFragment  =*/ "nose <>#%\"{}|^[]`",
    64         /*.pszUsername  =*/ "tt",
    65         /*.pszPassword  =*/ "tt",
     59        "foo://tt:[email protected]:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
     60        /*.pszScheme    =*/ "foo",
     61        /*.pszAuthority =*/ "tt:[email protected]:8042",
     62        /*.pszPath      =*/ "/over/ <>#%\"{}|^[]`/there",
     63        /*.pszQuery     =*/ "name= <>#%\"{}|^[]`ferret",
     64        /*.pszFragment  =*/ "nose <>#%\"{}|^[]`",
     65        /*.pszUsername  =*/ "tt",
     66        /*.pszPassword  =*/ "yt",
     67        /*.pszHost      =*/ "example.com",
    6668        /*.uPort        =*/ 8042,
    6769    },
    6870    {   /* #1 */
    69         "foo://tt:[email protected]:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret",
    70         /*.pszScheme    =*/ "foo",
    71         /*.pszAuthority =*/ "tt:[email protected]:8042",
    72         /*.pszPath      =*/ "/over/ <>#%\"{}|^[]`/there",
    73         /*.pszQuery     =*/ "name= <>#%\"{}|^[]`ferret",
    74         /*.pszFragment  =*/ NULL,
    75         /*.pszUsername  =*/ "tt",
    76         /*.pszPassword  =*/ "tt",
     71        "foo://tt:[email protected]:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret",
     72        /*.pszScheme    =*/ "foo",
     73        /*.pszAuthority =*/ "tt:[email protected]:8042",
     74        /*.pszPath      =*/ "/over/ <>#%\"{}|^[]`/there",
     75        /*.pszQuery     =*/ "name= <>#%\"{}|^[]`ferret",
     76        /*.pszFragment  =*/ NULL,
     77        /*.pszUsername  =*/ "tt",
     78        /*.pszPassword  =*/ "yt",
     79        /*.pszHost      =*/ "example.com",
    7780        /*.uPort        =*/ 8042,
    7881    },
    7982    {   /* #2 */
    80         "foo://tt:[email protected]:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there",
    81         /*.pszScheme    =*/ "foo",
    82         /*.pszAuthority =*/ "tt:[email protected]:8042",
    83         /*.pszPath      =*/ "/over/ <>#%\"{}|^[]`/there",
    84         /*.pszQuery     =*/ NULL,
    85         /*.pszFragment  =*/ NULL,
    86         /*.pszUsername  =*/ "tt",
    87         /*.pszPassword  =*/ "tt",
     83        "foo://tt:[email protected]:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there",
     84        /*.pszScheme    =*/ "foo",
     85        /*.pszAuthority =*/ "tt:[email protected]:8042",
     86        /*.pszPath      =*/ "/over/ <>#%\"{}|^[]`/there",
     87        /*.pszQuery     =*/ NULL,
     88        /*.pszFragment  =*/ NULL,
     89        /*.pszUsername  =*/ "tt",
     90        /*.pszPassword  =*/ "yt",
     91        /*.pszHost      =*/ "example.com",
    8892        /*.uPort        =*/ 8042,
    8993    },
     
    97101        /*.pszUsername  =*/ NULL,
    98102        /*.pszPassword  =*/ NULL,
     103        /*.pszHost      =*/ NULL,
    99104        /*.uPort        =*/ UINT32_MAX,
    100105    },
     
    108113        /*.pszUsername  =*/ NULL,
    109114        /*.pszPassword  =*/ NULL,
     115        /*.pszHost      =*/ NULL,
    110116        /*.uPort        =*/ UINT32_MAX,
    111117    },
     
    119125        /*.pszUsername  =*/ NULL,
    120126        /*.pszPassword  =*/ NULL,
     127        /*.pszHost      =*/ NULL,
    121128        /*.uPort        =*/ UINT32_MAX,
    122129    },
     
    130137        /*.pszUsername  =*/ NULL,
    131138        /*.pszPassword  =*/ NULL,
     139        /*.pszHost      =*/ NULL,
    132140        /*.uPort        =*/ UINT32_MAX,
    133141    },
     
    141149        /*.pszUsername  =*/ NULL,
    142150        /*.pszPassword  =*/ NULL,
     151        /*.pszHost      =*/ NULL,
    143152        /*.uPort        =*/ UINT32_MAX,
    144153    },
     
    152161        /*.pszUsername  =*/ NULL,
    153162        /*.pszPassword  =*/ NULL,
     163        /*.pszHost      =*/ NULL,
    154164        /*.uPort        =*/ UINT32_MAX,
    155165    },
    156166    {   /* #9 */
    157         "foo://tt:t[email protected]:8042/?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
    158         /*.pszScheme    =*/ "foo",
    159         /*.pszAuthority =*/ "tt:t[email protected]:8042",
     167        "foo://tt:y[email protected]:8042/?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
     168        /*.pszScheme    =*/ "foo",
     169        /*.pszAuthority =*/ "tt:y[email protected]:8042",
    160170        /*.pszPath      =*/ "/",
    161171        /*.pszQuery     =*/ "name= <>#%\"{}|^[]`ferret",
    162172        /*.pszFragment  =*/ "nose <>#%\"{}|^[]`",
    163173        /*.pszUsername  =*/ "tt",
    164         /*.pszPassword  =*/ "tt",
     174        /*.pszPassword  =*/ "yt",
     175        /*.pszHost      =*/ "example.com",
    165176        /*.uPort        =*/ 8042,
    166177    },
    167178    {   /* #10 */
    168         "foo://tt:t[email protected]:8042/",
    169         /*.pszScheme    =*/ "foo",
    170         /*.pszAuthority =*/ "tt:t[email protected]:8042",
     179        "foo://tt:y[email protected]:8042/",
     180        /*.pszScheme    =*/ "foo",
     181        /*.pszAuthority =*/ "tt:y[email protected]:8042",
    171182        /*.pszPath      =*/ "/",
    172183        /*.pszQuery     =*/ NULL,
    173184        /*.pszFragment  =*/ NULL,
    174185        /*.pszUsername  =*/ "tt",
    175         /*.pszPassword  =*/ "tt",
     186        /*.pszPassword  =*/ "yt",
     187        /*.pszHost      =*/ "example.com",
    176188        /*.uPort        =*/ 8042,
    177189    },
    178190    {   /* #11 */
    179         "foo://tt:[email protected]:8042?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
    180         /*.pszScheme    =*/ "foo",
    181         /*.pszAuthority =*/ "tt:[email protected]:8042",
    182         /*.pszPath      =*/ NULL,
    183         /*.pszQuery     =*/ "name= <>#%\"{}|^[]`ferret",
    184         /*.pszFragment  =*/ "nose <>#%\"{}|^[]`",
    185         /*.pszUsername  =*/ "tt",
    186         /*.pszPassword  =*/ "tt",
     191        "foo://tt:[email protected]:8042?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
     192        /*.pszScheme    =*/ "foo",
     193        /*.pszAuthority =*/ "tt:[email protected]:8042",
     194        /*.pszPath      =*/ NULL,
     195        /*.pszQuery     =*/ "name= <>#%\"{}|^[]`ferret",
     196        /*.pszFragment  =*/ "nose <>#%\"{}|^[]`",
     197        /*.pszUsername  =*/ "tt",
     198        /*.pszPassword  =*/ "yt",
     199        /*.pszHost      =*/ "example.com",
    187200        /*.uPort        =*/ 8042,
    188201    },
    189202    {   /* #12 */
    190         "foo://tt:[email protected]:8042#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
    191         /*.pszScheme    =*/ "foo",
    192         /*.pszAuthority =*/ "tt:[email protected]:8042",
    193         /*.pszPath      =*/ NULL,
    194         /*.pszQuery     =*/ NULL,
    195         /*.pszFragment  =*/ "nose <>#%\"{}|^[]`",
    196         /*.pszUsername  =*/ "tt",
    197         /*.pszPassword  =*/ "tt",
     203        "foo://tt:[email protected]:8042#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
     204        /*.pszScheme    =*/ "foo",
     205        /*.pszAuthority =*/ "tt:[email protected]:8042",
     206        /*.pszPath      =*/ NULL,
     207        /*.pszQuery     =*/ NULL,
     208        /*.pszFragment  =*/ "nose <>#%\"{}|^[]`",
     209        /*.pszUsername  =*/ "tt",
     210        /*.pszPassword  =*/ "yt",
     211        /*.pszHost      =*/ "example.com",
    198212        /*.uPort        =*/ 8042,
    199213    },
    200214    {   /* #13 */
    201         "foo://tt:[email protected]:8042",
    202         /*.pszScheme    =*/ "foo",
    203         /*.pszAuthority =*/ "tt:[email protected]:8042",
    204         /*.pszPath      =*/ NULL,
    205         /*.pszQuery     =*/ NULL,
    206         /*.pszFragment  =*/ NULL,
    207         /*.pszUsername  =*/ "tt",
    208         /*.pszPassword  =*/ "tt",
     215        "foo://tt:[email protected]:8042",
     216        /*.pszScheme    =*/ "foo",
     217        /*.pszAuthority =*/ "tt:[email protected]:8042",
     218        /*.pszPath      =*/ NULL,
     219        /*.pszQuery     =*/ NULL,
     220        /*.pszFragment  =*/ NULL,
     221        /*.pszUsername  =*/ "tt",
     222        /*.pszPassword  =*/ "yt",
     223        /*.pszHost      =*/ "example.com",
    209224        /*.uPort        =*/ 8042,
    210225    },
     
    218233        /*.pszUsername  =*/ NULL,
    219234        /*.pszPassword  =*/ NULL,
     235        /*.pszHost      =*/ NULL,
    220236        /*.uPort        =*/ UINT32_MAX,
    221237    },
     
    229245        /*.pszUsername  =*/ NULL,
    230246        /*.pszPassword  =*/ NULL,
     247        /*.pszHost      =*/ NULL,
    231248        /*.uPort        =*/ UINT32_MAX,
    232249    },
    233250};
    234251
    235 
    236 static const char *g_apcszTestURIs[] =
    237 {
    238     "foo://tt:[email protected]:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
    239     "foo://tt:[email protected]:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret",
    240     "foo://tt:[email protected]:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there",
    241     "foo:[email protected]",
    242     "foo:/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
    243     "foo:/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
    244     "urn:example:animal:ferret:nose",
    245     "foo:?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
    246     "foo:#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
    247     "foo://tt:[email protected]:8042/?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
    248     "foo://tt:[email protected]:8042/",
    249     "foo://tt:[email protected]:8042?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
    250     "foo://tt:[email protected]:8042#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
    251     "foo://tt:[email protected]:8042",
    252     "foo:///",
    253     "foo://"
    254 };
    255 
    256 static const char *g_apcszCreateURIs[][5] =
    257 {
    258     { "foo", "tt:[email protected]:8042", "/over/ <>#%\"{}|^[]`/there", "name= <>#%\"{}|^[]`ferret", "nose <>#%\"{}|^[]`" },
    259     { "foo", "tt:[email protected]:8042", "/over/ <>#%\"{}|^[]`/there", "name= <>#%\"{}|^[]`ferret", NULL },
    260     { "foo", "tt:[email protected]:8042", "/over/ <>#%\"{}|^[]`/there", NULL, NULL },
    261     { "foo", NULL, "[email protected]", NULL, NULL },
    262     { "foo", NULL, "/over/ <>#%\"{}|^[]`/there", "name= <>#%\"{}|^[]`ferret", "nose <>#%\"{}|^[]`" },
    263     { "foo", NULL, "/over/ <>#%\"{}|^[]`/there", NULL,  "nose <>#%\"{}|^[]`" },
    264     { "urn", NULL, "example:animal:ferret:nose", NULL, NULL },
    265     { "foo", NULL, NULL, "name= <>#%\"{}|^[]`ferret", "nose <>#%\"{}|^[]`" },
    266     { "foo", NULL, NULL, NULL, "nose <>#%\"{}|^[]`" },
    267     { "foo", "tt:[email protected]:8042", "/", "name= <>#%\"{}|^[]`ferret", "nose <>#%\"{}|^[]`" },
    268     { "foo", "tt:[email protected]:8042", "/", NULL, NULL },
    269     { "foo", "tt:[email protected]:8042", NULL, "name= <>#%\"{}|^[]`ferret", "nose <>#%\"{}|^[]`" },
    270     { "foo", "tt:[email protected]:8042", NULL, NULL, "nose <>#%\"{}|^[]`" },
    271     { "foo", "tt:[email protected]:8042", NULL, NULL, NULL },
    272     { "foo", "", "/", NULL, NULL },
    273     { "foo", "", NULL, NULL, NULL }
    274 };
    275252
    276253struct URIFILETEST
     
    289266};
    290267
    291 /**
    292  * Basic API checks.
    293  */
    294 static void tstScheme(size_t idxTest, const char *pszUri, const char *pszTest)
    295 {
    296     char *pszResult = RTUriScheme(pszUri);
    297     if (pszTest)
    298     {
    299         RTTESTI_CHECK_MSG_RETV(pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    300         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    301     }
    302     else
    303         RTTESTI_CHECK_MSG(!pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    304 
    305     if (pszResult)
    306         RTStrFree(pszResult);
    307 }
    308 
    309 static void tstAuthority(size_t idxTest, const char *pszUri, const char *pszTest)
    310 {
    311     char *pszResult = RTUriAuthority(pszUri);
    312     if (pszTest)
    313     {
    314         RTTESTI_CHECK_MSG_RETV(pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    315         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    316     }
    317     else
    318         RTTESTI_CHECK_MSG(!pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    319 
    320     if (pszResult)
    321         RTStrFree(pszResult);
    322 }
    323 
    324 static void tstAuthorityUsername(size_t idxTest, const char *pszUri, const char *pszTest)
    325 {
    326     char *pszResult = RTUriAuthorityUsername(pszUri);
    327     if (pszTest)
    328     {
    329         RTTESTI_CHECK_MSG_RETV(pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    330         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    331     }
    332     else
    333         RTTESTI_CHECK_MSG(!pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    334     RTStrFree(pszResult);
    335 }
    336 
    337 static void tstAuthorityPassword(size_t idxTest, const char *pszUri, const char *pszTest)
    338 {
    339     char *pszResult = RTUriAuthorityPassword(pszUri);
    340     if (pszTest)
    341     {
    342         RTTESTI_CHECK_MSG_RETV(pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    343         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    344     }
    345     else
    346         RTTESTI_CHECK_MSG(!pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    347     RTStrFree(pszResult);
    348 }
    349 
    350 static void tstAuthorityPort(size_t idxTest, const char *pszUri, uint32_t uTest)
    351 {
    352     uint32_t uResult = RTUriAuthorityPort(pszUri);
    353     RTTESTI_CHECK_MSG_RETV(uResult == uTest, ("#%u: Result %#x != %#x (%s)", idxTest, uResult, uTest, pszUri));
    354 }
    355 
    356 static void tstPath(size_t idxTest, const char *pszUri, const char *pszTest)
    357 {
    358     char *pszResult = RTUriPath(pszUri);
    359     if (pszTest)
    360     {
    361         RTTESTI_CHECK_MSG_RETV(pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    362         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    363     }
    364     else
    365         RTTESTI_CHECK_MSG(!pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    366 
    367     if (pszResult)
    368         RTStrFree(pszResult);
    369 }
    370 
    371 static void tstQuery(size_t idxTest, const char *pszUri, const char *pszTest)
    372 {
    373     char *pszResult = RTUriQuery(pszUri);
    374     if (pszTest)
    375     {
    376         RTTESTI_CHECK_MSG_RETV(pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    377         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    378     }
    379     else
    380         RTTESTI_CHECK_MSG(!pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    381 
    382     if (pszResult)
    383         RTStrFree(pszResult);
    384 }
    385 
    386 static void tstFragment(size_t idxTest, const char *pszUri, const char *pszTest)
    387 {
    388     char *pszResult = RTUriFragment(pszUri);
    389     if (pszTest)
    390     {
    391         RTTESTI_CHECK_MSG_RETV(pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    392         RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    393     }
    394     else
    395         RTTESTI_CHECK_MSG(!pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
    396 
    397     if (pszResult)
    398         RTStrFree(pszResult);
    399 }
     268
    400269
    401270static void tstCreate(size_t idxTest, const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery, const char *pszFragment, const char *pszTest)
     
    455324    RTTestBanner(hTest);
    456325
    457     /* Scheme */
    458     RTTestISub("RTUriScheme");
    459     for (uint32_t i = 0; i < RT_ELEMENTS(g_aTests); i++)
    460         tstScheme(i, g_aTests[i].pszUri, g_aTests[i].pszScheme);
    461 
    462     /* Authority */
    463     RTTestISub("RTUriAuthority");
     326    RTTestISub("RTUriParse & RTUriParsed*");
    464327    for (uint32_t i = 0; i < RT_ELEMENTS(g_aTests); i++)
    465328    {
    466         tstAuthority(i, g_aTests[i].pszUri, g_aTests[i].pszAuthority);
    467         tstAuthorityUsername(i, g_aTests[i].pszUri, g_aTests[i].pszUsername);
    468         tstAuthorityPassword(i, g_aTests[i].pszUri, g_aTests[i].pszPassword);
    469         tstAuthorityPort(i, g_aTests[i].pszUri, g_aTests[i].uPort);
     329        RTURIPARSED Parsed;
     330        RTTESTI_CHECK_RC(rc = RTUriParse(g_aTests[i].pszUri, &Parsed), VINF_SUCCESS);
     331        if (RT_SUCCESS(rc))
     332        {
     333#define CHECK_STR_API(a_Call, a_pszExpected) \
     334            do { \
     335                char *pszTmp = a_Call; \
     336                if (a_pszExpected) \
     337                { \
     338                    if (!pszTmp) \
     339                        RTTestIFailed("#%u: %s returns NULL, expected '%s'", i, #a_Call, a_pszExpected); \
     340                    else if (strcmp(pszTmp, a_pszExpected)) \
     341                            RTTestIFailed("#%u: %s returns '%s', expected '%s'", i, #a_Call, pszTmp, a_pszExpected); \
     342                } \
     343                else if (pszTmp) \
     344                    RTTestIFailed("#%u: %s returns '%s', expected NULL", i, #a_Call, pszTmp); \
     345                RTStrFree(pszTmp); \
     346            } while (0)
     347            CHECK_STR_API(RTUriParsedScheme(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszScheme);
     348            CHECK_STR_API(RTUriParsedAuthority(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszAuthority);
     349            CHECK_STR_API(RTUriParsedAuthorityUsername(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszUsername);
     350            CHECK_STR_API(RTUriParsedAuthorityPassword(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszPassword);
     351            CHECK_STR_API(RTUriParsedAuthorityHost(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszHost);
     352            CHECK_STR_API(RTUriParsedPath(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszPath);
     353            CHECK_STR_API(RTUriParsedQuery(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszQuery);
     354            CHECK_STR_API(RTUriParsedFragment(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszFragment);
     355            uint32_t uPort = RTUriParsedAuthorityPort(g_aTests[i].pszUri, &Parsed);
     356            if (uPort != g_aTests[i].uPort)
     357                RTTestIFailed("#%u: RTUriParsedAuthorityPort returns %#x, expected %#x", i, uPort, g_aTests[i].uPort);
     358        }
    470359    }
    471 
    472     /* Path */
    473     RTTestISub("RTUriPath");
    474     for (uint32_t i = 0; i < RT_ELEMENTS(g_aTests); i++)
    475         tstPath(i, g_aTests[i].pszUri, g_aTests[i].pszPath);
    476 
    477     /* Query */
    478     RTTestISub("RTUriQuery");
    479     for (uint32_t i = 0; i < RT_ELEMENTS(g_aTests); i++)
    480         tstQuery(i, g_aTests[i].pszUri, g_aTests[i].pszQuery);
    481 
    482     /* Fragment */
    483     RTTestISub("RTUriFragment");
    484     for (uint32_t i = 0; i < RT_ELEMENTS(g_aTests); i++)
    485         tstFragment(i, g_aTests[i].pszUri, g_aTests[i].pszFragment);
    486360
    487361    /* Creation */
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