RTDECL(int) RTPathParse(const char *pszPath, PRTPATHPARSED pParsed, size_t cbParsed, uint32_t fFlags) { /* * Input validation. */ AssertReturn(cbParsed >= RT_UOFFSETOF(RTPATHPARSED, aComps), VERR_INVALID_PARAMETER); AssertPtrReturn(pParsed, VERR_INVALID_POINTER); AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(*pszPath, VERR_PATH_ZERO_LENGTH); AssertReturn(RTPATH_STR_F_IS_VALID(fFlags, 0), VERR_INVALID_FLAGS); /* * Invoke the worker for the selected path style. */ switch (fFlags & RTPATH_STR_F_STYLE_MASK) { #if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) case RTPATH_STR_F_STYLE_HOST: #endif case RTPATH_STR_F_STYLE_DOS: return rtPathParseStyleDos(pszPath, pParsed, cbParsed, fFlags); #if !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS) case RTPATH_STR_F_STYLE_HOST: #endif case RTPATH_STR_F_STYLE_UNIX: return rtPathParseStyleUnix(pszPath, pParsed, cbParsed, fFlags); default: AssertFailedReturn(VERR_INVALID_FLAGS); /* impossible */ } }
RTDECL(char *) RTPathFilenameEx(const char *pszPath, uint32_t fFlags) { const char *psz = pszPath; const char *pszName = pszPath; Assert(RTPATH_STR_F_IS_VALID(fFlags, 0 /*no extra flags*/)); fFlags &= RTPATH_STR_F_STYLE_MASK; if (fFlags == RTPATH_STR_F_STYLE_HOST) fFlags = RTPATH_STYLE; if (fFlags == RTPATH_STR_F_STYLE_DOS) { for (;; psz++) { switch (*psz) { /* handle separators. */ case ':': case '\\': case '/': pszName = psz + 1; break; /* the end */ case '\0': if (*pszName) return (char *)(void *)pszName; return NULL; } } } else { Assert(fFlags == RTPATH_STR_F_STYLE_UNIX); for (;; psz++) { switch (*psz) { /* handle separators. */ case '/': pszName = psz + 1; break; /* the end */ case '\0': if (*pszName) return (char *)(void *)pszName; return NULL; } } } /* not reached */ }
RTDECL(int) RTPathSplitReassemble(PRTPATHSPLIT pSplit, uint32_t fFlags, char *pszDstPath, size_t cbDstPath) { /* * Input validation. */ AssertPtrReturn(pSplit, VERR_INVALID_POINTER); AssertReturn(pSplit->cComps > 0, VERR_INVALID_PARAMETER); AssertReturn(RTPATH_STR_F_IS_VALID(fFlags, 0) && !(fFlags & RTPATH_STR_F_MIDDLE), VERR_INVALID_FLAGS); AssertPtrReturn(pszDstPath, VERR_INVALID_POINTER); AssertReturn(cbDstPath > pSplit->cchPath, VERR_BUFFER_OVERFLOW); /* * Figure which slash to use. */ char chSlash; switch (fFlags & RTPATH_STR_F_STYLE_MASK) { case RTPATH_STR_F_STYLE_HOST: chSlash = RTPATH_SLASH; break; case RTPATH_STR_F_STYLE_DOS: chSlash = '\\'; break; case RTPATH_STR_F_STYLE_UNIX: chSlash = '/'; break; default: AssertFailedReturn(VERR_INVALID_FLAGS); /* impossible */ } /* * Do the joining. */ uint32_t const cchOrgPath = pSplit->cchPath; size_t cchDstPath = 0; uint32_t const cComps = pSplit->cComps; uint32_t idxComp = 0; char *pszDst = pszDstPath; size_t cchComp; if (RTPATH_PROP_HAS_ROOT_SPEC(pSplit->fProps)) { cchComp = strlen(pSplit->apszComps[0]); cchDstPath += cchComp; AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER); memcpy(pszDst, pSplit->apszComps[0], cchComp); /* fix the slashes */ char chOtherSlash = chSlash == '\\' ? '/' : '\\'; while (cchComp-- > 0) { if (*pszDst == chOtherSlash) *pszDst = chSlash; pszDst++; } idxComp = 1; } while (idxComp < cComps) { cchComp = strlen(pSplit->apszComps[idxComp]); cchDstPath += cchComp; AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER); memcpy(pszDst, pSplit->apszComps[idxComp], cchComp); pszDst += cchComp; idxComp++; if (idxComp != cComps || (pSplit->fProps & RTPATH_PROP_DIR_SLASH)) { cchDstPath++; AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER); *pszDst++ = chSlash; } } *pszDst = '\0'; return VINF_SUCCESS; }
RTDECL(int) RTPathSplit(const char *pszPath, PRTPATHSPLIT pSplit, size_t cbSplit, uint32_t fFlags) { /* * Input validation. */ AssertReturn(cbSplit >= RT_UOFFSETOF(RTPATHSPLIT, apszComps), VERR_INVALID_PARAMETER); AssertPtrReturn(pSplit, VERR_INVALID_POINTER); AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(*pszPath, VERR_PATH_ZERO_LENGTH); AssertReturn(RTPATH_STR_F_IS_VALID(fFlags, 0), VERR_INVALID_FLAGS); /* * Use RTPathParse to do the parsing. * - This makes the ASSUMPTION that the output of this function is greater * or equal to that of RTPathParsed. * - We're aliasing the buffer here, so use volatile to avoid issues due to * compiler optimizations. */ RTPATHPARSED volatile *pParsedVolatile = (RTPATHPARSED volatile *)pSplit; RTPATHSPLIT volatile *pSplitVolatile = (RTPATHSPLIT volatile *)pSplit; AssertCompile(sizeof(*pParsedVolatile) <= sizeof(*pSplitVolatile)); AssertCompile(sizeof(pParsedVolatile->aComps[0]) <= sizeof(pSplitVolatile->apszComps[0])); int rc = RTPathParse(pszPath, (PRTPATHPARSED)pParsedVolatile, cbSplit, fFlags); if (RT_FAILURE(rc) && rc != VERR_BUFFER_OVERFLOW) return rc; /* * Calculate the required buffer space. */ uint16_t const cComps = pParsedVolatile->cComps; uint16_t const fProps = pParsedVolatile->fProps; uint16_t const cchPath = pParsedVolatile->cchPath; uint16_t const offSuffix = pParsedVolatile->offSuffix; uint32_t cbNeeded = RT_OFFSETOF(RTPATHSPLIT, apszComps[cComps]) + cchPath + RTPATH_PROP_FIRST_NEEDS_NO_SLASH(fProps) /* zero terminator for root spec. */ - RT_BOOL(fProps & RTPATH_PROP_DIR_SLASH) /* counted by cchPath, not included in the comp str. */ + 1; /* zero terminator. */ if (cbNeeded > cbSplit) { pSplitVolatile->cbNeeded = cbNeeded; return VERR_BUFFER_OVERFLOW; } Assert(RT_SUCCESS(rc)); /* * Convert the array and copy the strings, both backwards. */ char *psz = (char *)pSplit + cbNeeded; uint32_t idxComp = cComps - 1; /* the final component first (because of suffix handling). */ uint16_t offComp = pParsedVolatile->aComps[idxComp].off; uint16_t cchComp = pParsedVolatile->aComps[idxComp].cch; *--psz = '\0'; psz -= cchComp; memcpy(psz, &pszPath[offComp], cchComp); pSplitVolatile->apszComps[idxComp] = psz; char *pszSuffix; if (offSuffix >= offComp + cchComp) pszSuffix = &psz[cchComp]; else pszSuffix = &psz[offSuffix - offComp]; /* the remainder */ while (idxComp-- > 0) { offComp = pParsedVolatile->aComps[idxComp].off; cchComp = pParsedVolatile->aComps[idxComp].cch; *--psz = '\0'; psz -= cchComp; memcpy(psz, &pszPath[offComp], cchComp); pSplitVolatile->apszComps[idxComp] = psz; } /* * Store / reshuffle the non-array bits. This MUST be done after finishing * the array processing because there may be members in RTPATHSPLIT * overlapping the array of RTPATHPARSED. */ AssertCompileMembersSameSizeAndOffset(RTPATHPARSED, cComps, RTPATHSPLIT, cComps); Assert(pSplitVolatile->cComps == cComps); AssertCompileMembersSameSizeAndOffset(RTPATHPARSED, fProps, RTPATHSPLIT, fProps); Assert(pSplitVolatile->fProps == fProps); AssertCompileMembersSameSizeAndOffset(RTPATHPARSED, cchPath, RTPATHSPLIT, cchPath); Assert(pSplitVolatile->cchPath == cchPath); pSplitVolatile->u16Reserved = 0; pSplitVolatile->cbNeeded = cbNeeded; pSplitVolatile->pszSuffix = pszSuffix; return rc; }