Changeset 57720 in vbox for trunk/src/VBox/Runtime/common/misc/uri.cpp
- Timestamp:
- Sep 11, 2015 2:49:21 PM (10 years ago)
- svn:sync-xref-src-repo-rev:
- 102634
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/misc/uri.cpp
r57358 r57720 31 31 #include <iprt/uri.h> 32 32 33 #include <iprt/assert.h> 34 #include <iprt/ctype.h> 35 #include <iprt/path.h> 33 36 #include <iprt/string.h> 34 #include <iprt/mem.h>35 #include <iprt/path.h>36 #include <iprt/stream.h>37 37 38 38 /* General URI format: … … 47 47 */ 48 48 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 49 111 50 112 /********************************************************************************************************************************* 51 * Private RTUri helper*113 * Internal Functions * 52 114 *********************************************************************************************************************************/ 53 115 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 */ 60 123 #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) == '`' ) 66 129 67 130 static char *rtUriPercentEncodeN(const char *pszString, size_t cchMax) … … 74 137 size_t cbLen = RT_MIN(strlen(pszString), cchMax); 75 138 /* 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); 77 140 if (!pszNew) 78 141 return NULL; 142 79 143 char *pszRes = NULL; 80 144 size_t iIn = 0; 81 145 size_t iOut = 0; 82 while (iIn < cbLen)146 while (iIn < cbLen) 83 147 { 84 148 if (URI_EXCLUDED(pszString[iIn])) … … 117 181 return NULL; 118 182 119 int rc = VINF_SUCCESS;120 size_t cbLen = RT_MIN(strlen(pszString), cchMax);121 183 /* 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); 123 187 if (!pszNew) 124 188 return NULL; 189 190 int rc = VINF_SUCCESS; 125 191 char *pszRes = NULL; 126 192 size_t iIn = 0; 127 193 size_t iOut = 0; 128 while (iIn < cbLen)194 while (iIn < cchLen) 129 195 { 130 196 if (pszString[iIn] == '%') … … 169 235 static bool rtUriFindSchemeEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd) 170 236 { 237 /* The scheme has to end with ':'. */ 171 238 size_t i = iStart; 172 /* The scheme has to end with ':'. */ 173 while(i < iStart + cbLen) 239 while (i < iStart + cbLen) 174 240 { 175 241 if (pszUri[i] == ':') … … 199 265 static bool rtUriFindAuthorityEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd) 200 266 { 267 /* The authority can end with '/' || '?' || '#'. */ 201 268 size_t i = iStart; 202 /* The authority can end with '/' || '?' || '#'. */ 203 while(i < iStart + cbLen) 269 while (i < iStart + cbLen) 204 270 { 205 271 if ( pszUri[i] == '/' … … 224 290 return true; 225 291 } 292 226 293 /* '?' || '#' means there is no path. */ 227 294 if ( cbLen >= 1 … … 229 296 || pszUri[iStart] == '#')) 230 297 return false; 298 231 299 /* All other values are allowed. */ 232 300 *piStart = iStart; … … 236 304 static bool rtUriFindPathEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd) 237 305 { 306 /* The path can end with '?' || '#'. */ 238 307 size_t i = iStart; 239 /* The path can end with '?' || '#'. */ 240 while(i < iStart + cbLen) 308 while (i < iStart + cbLen) 241 309 { 242 310 if ( pszUri[i] == '?' … … 251 319 } 252 320 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; 321 static 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; 291 503 } 292 504 293 505 294 506 /********************************************************************************************************************************* 295 * Public RTUri interface*507 * Generic URI APIs * 296 508 *********************************************************************************************************************************/ 297 509 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) 510 RTR3DECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery, 511 const char *pszFragment) 304 512 { 305 513 if (!pszScheme) /* Scheme is minimum requirement */ … … 346 554 } 347 555 348 char *pszTmp = pszResult = (char *)RTMemAllocZ(cbSize);556 char *pszTmp = pszResult = (char *)RTStrAlloc(cbSize); 349 557 if (!pszResult) 350 558 break; 559 RT_BZERO(pszTmp, cbSize); 560 351 561 /* Compose the target uri string. */ 352 562 RTStrCatP(&pszTmp, &cbSize, pszScheme); … … 371 581 RTStrCatP(&pszTmp, &cbSize, pszFragment1); 372 582 } 373 } while (0);583 } while (0); 374 584 375 585 /* Cleanup */ … … 411 621 RTR3DECL(char *) RTUriAuthority(const char *pszUri) 412 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) 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 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) 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 723 RTR3DECL(char *) RTUriFilePath(const char *pszUri, uint32_t uFormat) 724 { 725 return RTUriFileNPath(pszUri, uFormat, RTSTR_MAX); 726 } 727 728 RTR3DECL(char *) RTUriFileNPath(const char *pszUri, uint32_t uFormat, size_t cchMax) 729 { 413 730 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); 435 767 } 436 768 return NULL; 437 769 } 438 770 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 else449 ++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 path457 * 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 else486 ++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 path494 * 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 query505 * 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 else534 ++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 path542 * 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 query553 * 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 fragment564 * 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 the575 * 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 do596 {597 /* Create the percent encoded strings and calculate the necessary uri598 * 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 else637 ++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 path649 * 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_WINDOWS662 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_UNIX668 && 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 else681 {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.