RTR3DECL(char *) RTUriFileCreate(const char *pszPath) { if (!pszPath) return NULL; char *pszResult = 0; char *pszPath1 = 0; do { /* Create the percent encoded strings and calculate the necessary uri * length. */ pszPath1 = rtUriPercentEncodeN(pszPath, RTSTR_MAX); if (!pszPath1) break; size_t cbSize = 7 /* file:// */ + strlen(pszPath1) + 1; /* plus zero byte */ if (pszPath1[0] != '/') ++cbSize; char *pszTmp = pszResult = (char*)RTMemAllocZ(cbSize); if (!pszResult) break; /* Compose the target uri string. */ RTStrCatP(&pszTmp, &cbSize, "file://"); if (pszPath1[0] != '/') RTStrCatP(&pszTmp, &cbSize, "/"); RTStrCatP(&pszTmp, &cbSize, pszPath1); }while (0); /* Cleanup */ if (pszPath1) RTStrFree(pszPath1); return pszResult; }
RTR3DECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery, const char *pszFragment) { if (!pszScheme) /* Scheme is minimum requirement */ return NULL; char *pszResult = 0; char *pszAuthority1 = 0; char *pszPath1 = 0; char *pszQuery1 = 0; char *pszFragment1 = 0; do { /* Create the percent encoded strings and calculate the necessary uri * length. */ size_t cbSize = strlen(pszScheme) + 1 + 1; /* plus zero byte */ if (pszAuthority) { pszAuthority1 = rtUriPercentEncodeN(pszAuthority, RTSTR_MAX); if (!pszAuthority1) break; cbSize += strlen(pszAuthority1) + 2; } if (pszPath) { pszPath1 = rtUriPercentEncodeN(pszPath, RTSTR_MAX); if (!pszPath1) break; cbSize += strlen(pszPath1); } if (pszQuery) { pszQuery1 = rtUriPercentEncodeN(pszQuery, RTSTR_MAX); if (!pszQuery1) break; cbSize += strlen(pszQuery1) + 1; } if (pszFragment) { pszFragment1 = rtUriPercentEncodeN(pszFragment, RTSTR_MAX); if (!pszFragment1) break; cbSize += strlen(pszFragment1) + 1; } char *pszTmp = pszResult = (char*)RTMemAllocZ(cbSize); if (!pszResult) break; /* Compose the target uri string. */ RTStrCatP(&pszTmp, &cbSize, pszScheme); RTStrCatP(&pszTmp, &cbSize, ":"); if (pszAuthority1) { RTStrCatP(&pszTmp, &cbSize, "//"); RTStrCatP(&pszTmp, &cbSize, pszAuthority1); } if (pszPath1) { RTStrCatP(&pszTmp, &cbSize, pszPath1); } if (pszQuery1) { RTStrCatP(&pszTmp, &cbSize, "?"); RTStrCatP(&pszTmp, &cbSize, pszQuery1); } if (pszFragment1) { RTStrCatP(&pszTmp, &cbSize, "#"); RTStrCatP(&pszTmp, &cbSize, pszFragment1); } }while (0); /* Cleanup */ if (pszAuthority1) RTStrFree(pszAuthority1); if (pszPath1) RTStrFree(pszPath1); if (pszQuery1) RTStrFree(pszQuery1); if (pszFragment1) RTStrFree(pszFragment1); return pszResult; }
RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst, const char *pszPathFrom, const char *pszPathTo) { int rc = VINF_SUCCESS; AssertPtrReturn(pszPathDst, VERR_INVALID_POINTER); AssertReturn(cbPathDst, VERR_INVALID_PARAMETER); AssertPtrReturn(pszPathFrom, VERR_INVALID_POINTER); AssertPtrReturn(pszPathTo, VERR_INVALID_POINTER); AssertReturn(RTPathStartsWithRoot(pszPathFrom), VERR_INVALID_PARAMETER); AssertReturn(RTPathStartsWithRoot(pszPathTo), VERR_INVALID_PARAMETER); AssertReturn(RTStrCmp(pszPathFrom, pszPathTo), VERR_INVALID_PARAMETER); /* * Check for different root specifiers (drive letters), creating a relative path doesn't work here. * @todo: How to handle case insensitive root specifiers correctly? */ size_t offRootFrom = rtPathRootSpecLen(pszPathFrom); size_t offRootTo = rtPathRootSpecLen(pszPathTo); if ( offRootFrom != offRootTo || RTStrNCmp(pszPathFrom, pszPathTo, offRootFrom)) return VERR_NOT_SUPPORTED; /* Filter out the parent path which is equal to both paths. */ while ( *pszPathFrom == *pszPathTo && *pszPathFrom != '\0' && *pszPathTo != '\0') { pszPathFrom++; pszPathTo++; } /* * Because path components can start with an equal string but differ afterwards we * need to go back to the beginning of the current component. */ while (!RTPATH_IS_SEP(*pszPathFrom)) pszPathFrom--; pszPathFrom++; /* Skip path separator. */ while (!RTPATH_IS_SEP(*pszPathTo)) pszPathTo--; pszPathTo++; /* Skip path separator. */ /* Paths point to the first non equal component now. */ char aszPathTmp[RTPATH_MAX + 1]; unsigned offPathTmp = 0; /* Create the part to go up from pszPathFrom. */ while (*pszPathFrom != '\0') { while ( !RTPATH_IS_SEP(*pszPathFrom) && *pszPathFrom != '\0') pszPathFrom++; if (RTPATH_IS_SEP(*pszPathFrom)) { if (offPathTmp + 3 >= sizeof(aszPathTmp) - 1) return VERR_FILENAME_TOO_LONG; aszPathTmp[offPathTmp++] = '.'; aszPathTmp[offPathTmp++] = '.'; aszPathTmp[offPathTmp++] = RTPATH_SLASH; pszPathFrom++; } } aszPathTmp[offPathTmp] = '\0'; /* Now append the rest of pszPathTo to the final path. */ char *pszPathTmp = &aszPathTmp[offPathTmp]; size_t cbPathTmp = sizeof(aszPathTmp) - offPathTmp - 1; rc = RTStrCatP(&pszPathTmp, &cbPathTmp, pszPathTo); if (RT_SUCCESS(rc)) { *pszPathTmp = '\0'; size_t cchPathTmp = strlen(aszPathTmp); if (cchPathTmp >= cbPathDst) return VERR_BUFFER_OVERFLOW; memcpy(pszPathDst, aszPathTmp, cchPathTmp + 1); } else rc = VERR_FILENAME_TOO_LONG; return rc; }