Changeset 76589 in vbox for trunk/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp
- Timestamp:
- Jan 1, 2019 8:56:07 AM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp
r76553 r76589 31 31 #include "internal/iprt.h" 32 32 #include <iprt/path.h> 33 33 34 #include <iprt/assert.h> 35 #if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS 36 # include <iprt/ctype.h> 37 #endif 34 38 #include <iprt/err.h> 35 39 #include <iprt/string.h> … … 39 43 40 44 RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst, 41 const char *pszPathFrom, 45 const char *pszPathFrom, bool fFromFile, 42 46 const char *pszPathTo) 43 47 { 44 int rc = VINF_SUCCESS;45 46 48 AssertPtrReturn(pszPathDst, VERR_INVALID_POINTER); 47 49 AssertReturn(cbPathDst, VERR_INVALID_PARAMETER); 48 50 AssertPtrReturn(pszPathFrom, VERR_INVALID_POINTER); 49 51 AssertPtrReturn(pszPathTo, VERR_INVALID_POINTER); 50 AssertReturn(RTPathStartsWithRoot(pszPathFrom), VERR_INVALID_PARAMETER);51 AssertReturn(RTPathStartsWithRoot(pszPathTo), VERR_INVALID_PARAMETER);52 AssertReturn(RTStrCmp(pszPathFrom, pszPathTo), VERR_INVALID_PARAMETER);53 52 54 53 /* 55 54 * Check for different root specifiers (drive letters), creating a relative path doesn't work here. 56 * @todo: How to handle case insensitive root specifiers correctly?57 55 */ 58 56 size_t offRootFrom = rtPathRootSpecLen(pszPathFrom); 57 AssertReturn(offRootFrom > 0, VERR_INVALID_PARAMETER); 58 59 59 size_t offRootTo = rtPathRootSpecLen(pszPathTo); 60 61 if ( offRootFrom != offRootTo 62 || RTStrNCmp(pszPathFrom, pszPathTo, offRootFrom)) 60 AssertReturn(offRootTo > 0, VERR_INVALID_PARAMETER); 61 62 63 /** @todo correctly deal with extra root slashes! */ 64 if (offRootFrom != offRootTo) 63 65 return VERR_NOT_SUPPORTED; 64 66 65 /* Filter out the parent path which is equal to both paths. */ 66 while ( *pszPathFrom == *pszPathTo 67 && *pszPathFrom != '\0' 68 && *pszPathTo != '\0') 69 { 70 pszPathFrom++; 71 pszPathTo++; 72 } 67 #if RTPATH_STYLE != RTPATH_STR_F_STYLE_DOS 68 if (RTStrNCmp(pszPathFrom, pszPathTo, offRootFrom)) 69 return VERR_NOT_SUPPORTED; 70 #else 71 if (RTStrNICmp(pszPathFrom, pszPathTo, offRootFrom)) 72 for (size_t off = 0; off < offRootFrom; off++) 73 { 74 char const chFrom = pszPathFrom[off]; 75 char const chTo = pszPathTo[off]; 76 if ( chFrom != chTo 77 && RT_C_TO_LOWER(chFrom) != RT_C_TO_LOWER(chTo) /** @todo proper case insensitivity! */ 78 && (!RTPATH_IS_SLASH(chFrom) || !RTPATH_IS_SLASH(chTo)) ) 79 return VERR_NOT_SUPPORTED; 80 } 81 #endif 82 83 pszPathFrom += offRootFrom; 84 pszPathTo += offRootTo; 73 85 74 86 /* 75 * Because path components can start with an equal string but differ afterwards we 76 * need to go back to the beginning of the current component. 87 * Skip out the part of the path which is equal to both. 77 88 */ 78 while (!RTPATH_IS_SEP(*pszPathFrom)) 79 pszPathFrom--; 80 81 pszPathFrom++; /* Skip path separator. */ 82 83 while (!RTPATH_IS_SEP(*pszPathTo)) 84 pszPathTo--; 85 86 pszPathTo++; /* Skip path separator. */ 89 const char *pszStartOfFromComp = pszPathFrom; 90 for (;;) 91 { 92 char const chFrom = *pszPathFrom; 93 char const chTo = *pszPathTo; 94 if (!RTPATH_IS_SLASH(chFrom)) 95 { 96 if (chFrom == chTo) 97 { 98 if (chFrom) 99 { /* likely */ } 100 else 101 { 102 /* Special case: The two paths are equal. */ 103 if (fFromFile) 104 { 105 size_t cchComp = pszPathFrom - pszStartOfFromComp; 106 if (cchComp < cbPathDst) 107 { 108 memcpy(pszPathDst, pszStartOfFromComp, cchComp); 109 pszPathDst[cchComp] = '\0'; 110 return VINF_SUCCESS; 111 } 112 } 113 else if (sizeof(".") <= cbPathDst) 114 { 115 memcpy(pszPathDst, ".", sizeof(".")); 116 return VINF_SUCCESS; 117 } 118 return VERR_BUFFER_OVERFLOW; 119 } 120 } 121 #if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS 122 else if (RT_C_TO_LOWER(chFrom) == RT_C_TO_LOWER(chTo)) 123 { /* if not likely, then simpler code structure wise. */ } 124 #endif 125 else if (chFrom != '\0' || !RTPATH_IS_SLASH(chTo) || fFromFile) 126 break; 127 else 128 { 129 pszStartOfFromComp = pszPathFrom; 130 do 131 pszPathTo++; 132 while (RTPATH_IS_SLASH(*pszPathTo)); 133 break; 134 } 135 pszPathFrom++; 136 pszPathTo++; 137 } 138 else if (RTPATH_IS_SLASH(chTo)) 139 { 140 /* Both have slashes. Skip any additional ones before taking down 141 the start of the component for rewinding purposes. */ 142 do 143 pszPathTo++; 144 while (RTPATH_IS_SLASH(*pszPathTo)); 145 do 146 pszPathFrom++; 147 while (RTPATH_IS_SLASH(*pszPathFrom)); 148 pszStartOfFromComp = pszPathFrom; 149 } 150 else 151 break; 152 } 153 154 /* Rewind to the start of the current component. */ 155 pszPathTo -= pszPathFrom - pszStartOfFromComp; 156 pszPathFrom = pszStartOfFromComp; 87 157 88 158 /* Paths point to the first non equal component now. */ 89 char aszPathTmp[RTPATH_MAX + 1]; 90 unsigned offPathTmp = 0; 159 160 /* 161 * Constructure the relative path. 162 */ 91 163 92 164 /* Create the part to go up from pszPathFrom. */ 165 unsigned offDst = 0; 166 167 if (!fFromFile && *pszPathFrom != '\0') 168 { 169 if (offDst + 3 < cbPathDst) 170 { 171 pszPathDst[offDst++] = '.'; 172 pszPathDst[offDst++] = '.'; 173 pszPathDst[offDst++] = RTPATH_SLASH; 174 } 175 else 176 return VERR_BUFFER_OVERFLOW; 177 } 178 93 179 while (*pszPathFrom != '\0') 94 180 { 95 while ( !RTPATH_IS_SEP(*pszPathFrom) 96 && *pszPathFrom != '\0') 181 char ch; 182 while ( (ch = *pszPathFrom) != '\0' 183 && !RTPATH_IS_SLASH(*pszPathFrom)) 97 184 pszPathFrom++; 98 99 if (RTPATH_IS_SEP(*pszPathFrom)) 100 { 101 if (offPathTmp + 3 >= sizeof(aszPathTmp) - 1) 102 return VERR_FILENAME_TOO_LONG; 103 aszPathTmp[offPathTmp++] = '.'; 104 aszPathTmp[offPathTmp++] = '.'; 105 aszPathTmp[offPathTmp++] = RTPATH_SLASH; 185 while ( (ch = *pszPathFrom) != '\0' 186 && RTPATH_IS_SLASH(ch)) 106 187 pszPathFrom++; 107 } 108 } 109 110 aszPathTmp[offPathTmp] = '\0'; 188 if (!ch) 189 break; 190 191 if (offDst + 3 < cbPathDst) 192 { 193 pszPathDst[offDst++] = '.'; 194 pszPathDst[offDst++] = '.'; 195 pszPathDst[offDst++] = RTPATH_SLASH; 196 } 197 else 198 return VERR_BUFFER_OVERFLOW; 199 } 111 200 112 201 /* Now append the rest of pszPathTo to the final path. */ 113 char *pszPathTmp = &aszPathTmp[offPathTmp]; 114 size_t cbPathTmp = sizeof(aszPathTmp) - offPathTmp - 1; 115 rc = RTStrCatP(&pszPathTmp, &cbPathTmp, pszPathTo); 116 if (RT_SUCCESS(rc)) 117 { 118 *pszPathTmp = '\0'; 119 120 size_t cchPathTmp = strlen(aszPathTmp); 121 if (cchPathTmp >= cbPathDst) 122 return VERR_BUFFER_OVERFLOW; 123 memcpy(pszPathDst, aszPathTmp, cchPathTmp + 1); 124 } 125 else 126 rc = VERR_FILENAME_TOO_LONG; 127 128 return rc; 202 size_t cchTo = strlen(pszPathTo); 203 if (offDst + cchTo <= cbPathDst) 204 { 205 memcpy(&pszPathDst[offDst], pszPathTo, cchTo); 206 pszPathDst[offDst + cchTo] = '\0'; 207 return VINF_SUCCESS; 208 } 209 return VERR_BUFFER_OVERFLOW; 129 210 } 130 211
Note:
See TracChangeset
for help on using the changeset viewer.