|
31 | 31 | * <li>the base name - file</li> |
32 | 32 | * <li>the extension - txt</li> |
33 | 33 | * </ul> |
34 | | - * The class only supports Unix and Windows style names. |
| 34 | + * The class only supports Unix and Windows style names. Prefixes are matched as follows: |
| 35 | + * <pre> |
| 36 | + * Windows style: |
| 37 | + * a\b\c.txt --> "" --> relative |
| 38 | + * \a\b\c.txt --> "\" --> drive relative |
| 39 | + * C:\a\b\c.txt --> "C:\" --> absolute |
| 40 | + * \\server\a\b\c.txt --> "\\server\" --> UNC |
| 41 | + * |
| 42 | + * Unix style: |
| 43 | + * a/b/c.txt --> "" --> relative |
| 44 | + * /a/b/c.txt --> "/" --> absolute |
| 45 | + * ~/a/b/c.txt --> "~/" --> current user relative |
| 46 | + * ~user/a/b/c.txt --> "~user/" --> named user relative |
| 47 | + * </pre> |
| 48 | + * |
35 | 49 | * </p> |
36 | 50 | * <h3>Origin of code</h3> |
37 | 51 | * <ul> |
38 | 52 | * <li>Commons Utils</li> |
39 | 53 | * <li>Alexandria's FileUtils</li> |
40 | 54 | * <li>Avalon Excalibur's IO</li> |
| 55 | + * <li>Tomcat</li> |
41 | 56 | * </ul> |
42 | 57 | * |
43 | 58 | * @author <a href="mailto:burton@relativity.yi.org">Kevin A. Burton</A> |
|
50 | 65 | * @author Martin Cooper |
51 | 66 | * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a> |
52 | 67 | * @author Stephen Colebourne |
53 | | - * @version $Id: FilenameUtils.java,v 1.29 2004/11/27 01:22:05 scolebourne Exp $ |
| 68 | + * @version $Id: FilenameUtils.java,v 1.30 2004/11/27 17:00:51 scolebourne Exp $ |
54 | 69 | * @since Commons IO 1.1 |
55 | 70 | */ |
56 | 71 | public class FilenameUtils { |
@@ -90,14 +105,15 @@ public class FilenameUtils { |
90 | 105 | /** |
91 | 106 | * Instances should NOT be constructed in standard programming. |
92 | 107 | */ |
93 | | - public FilenameUtils() { } |
| 108 | + public FilenameUtils() { |
| 109 | + } |
94 | 110 |
|
95 | 111 | //----------------------------------------------------------------------- |
96 | 112 | /** |
97 | 113 | * Checks if the character is a separator. |
98 | 114 | * |
99 | 115 | * @param ch the character to check |
100 | | - * @return true if it is a separators |
| 116 | + * @return true if it is a separator character |
101 | 117 | */ |
102 | 118 | private static boolean isSeparator(char ch) { |
103 | 119 | return (ch == UNIX_SEPARATOR) || (ch == WINDOWS_SEPARATOR); |
@@ -135,9 +151,10 @@ private static boolean isSeparator(char ch) { |
135 | 151 | * ~/foo/../bar --> ~/bar |
136 | 152 | * ~/../bar --> null |
137 | 153 | * </pre> |
| 154 | + * (Note the file separator returned will be correct for windows/unix) |
138 | 155 | * |
139 | 156 | * @param filename the filename to normalize, null returns null |
140 | | - * @return the normalized String, or null if too many ..'s. |
| 157 | + * @return the normalized String, or null if invalid |
141 | 158 | */ |
142 | 159 | public static String normalize(String filename) { |
143 | 160 | if (filename == null) { |
@@ -215,49 +232,53 @@ public static String normalize(String filename) { |
215 | 232 | } |
216 | 233 |
|
217 | 234 | /** |
218 | | - * Will concatenate 2 paths. Paths with <code>..</code> will be |
219 | | - * properly handled. The path separator between the 2 paths is the |
220 | | - * system default path separator. |
221 | | - * |
222 | | - * <p>Eg. on UNIX,<br /> |
223 | | - * <code>/a/b/c</code> + <code>d</code> = <code>/a/b/d</code><br /> |
224 | | - * <code>/a/b/c</code> + <code>../d</code> = <code>/a/d</code><br /> |
225 | | - * </p> |
226 | | - * |
227 | | - * <p>Eg. on Microsoft Windows,<br /> |
228 | | - * <code>C:\a\b\c</code> + <code>d</code> = <code>C:\a\b\d</code><br /> |
229 | | - * <code>C:\a\b\c</code> + <code>..\d</code> = <code>C:\a\d</code><br /> |
230 | | - * <code>/a/b/c</code> + <code>d</code> = <code>/a/b\d</code><br /> |
231 | | - * </p> |
232 | | - * |
233 | | - * Thieved from Tomcat sources... |
| 235 | + * Concatenates two paths using normal command line style rules. |
| 236 | + * <p> |
| 237 | + * The first argument is the base path, the second is the path to concatenate. |
| 238 | + * The returned path is always normalized via {@link #normalize(String)}, |
| 239 | + * thus <code>..</code> is handled. |
| 240 | + * <p> |
| 241 | + * If <code>pathToAdd</code> is absolute (has a prefix), then it will |
| 242 | + * be normalized and returned. |
| 243 | + * Otherwise, the paths will be joined, normalized and returned. |
| 244 | + * <pre> |
| 245 | + * /foo/ + bar --> /foo/bar |
| 246 | + * /foo/a + bar --> /foo/a/bar |
| 247 | + * /foo/c.txt + bar --> /foo/c.txt/bar |
| 248 | + * /foo/ + ../bar --> /bar |
| 249 | + * /foo/ + ../../bar --> null |
| 250 | + * /foo/ + /bar --> /bar |
| 251 | + * /foo/.. + /bar --> /bar |
| 252 | + * </pre> |
| 253 | + * Note that the first parameter must be a path. If it ends with a name, then |
| 254 | + * the name will be built into the concatenated path. If this might be a problem, |
| 255 | + * use {@link #getFullPath(String)} on the base path argument. |
234 | 256 | * |
235 | | - * @param lookupPath the base path to attach to |
236 | | - * @param path path the second path to attach to the first |
237 | | - * @return The concatenated paths, or null if error occurs |
| 257 | + * @param basePath the base path to attach to, always treated as a path |
| 258 | + * @param pathToAdd path the second path to attach to the first |
| 259 | + * @return the concatenated path, or null if invalid |
238 | 260 | */ |
239 | | - // TODO UNIX/Windows only. Is this a problem? |
240 | | - public static String catPath(String lookupPath, String path) { |
241 | | - // Cut off the last slash and everything beyond |
242 | | - int index = indexOfLastSeparator(lookupPath); |
243 | | - String lookup = lookupPath.substring(0, index); |
244 | | - String pth = path; |
245 | | - |
246 | | - // Deal with .. by chopping dirs off the lookup path |
247 | | - while (pth.startsWith("../") || pth.startsWith("..\\")) { |
248 | | - if (lookup.length() > 0) { |
249 | | - index = indexOfLastSeparator(lookup); |
250 | | - lookup = lookup.substring(0, index); |
251 | | - } else { |
252 | | - // More ..'s than dirs, return null |
253 | | - return null; |
254 | | - } |
255 | | - |
256 | | - pth = pth.substring(3); |
| 261 | + public static String concat(String basePath, String pathToAdd) { |
| 262 | + int prefix = getPrefixLength(pathToAdd); |
| 263 | + if (prefix < 0) { |
| 264 | + return null; |
| 265 | + } |
| 266 | + if (prefix > 0) { |
| 267 | + return normalize(pathToAdd); |
| 268 | + } |
| 269 | + if (basePath == null) { |
| 270 | + return null; |
| 271 | + } |
| 272 | + int len = basePath.length(); |
| 273 | + if (len == 0) { |
| 274 | + return normalize(pathToAdd); |
| 275 | + } |
| 276 | + char ch = basePath.charAt(len - 1); |
| 277 | + if (isSeparator(basePath.charAt(len - 1))) { |
| 278 | + return normalize(basePath + pathToAdd); |
| 279 | + } else { |
| 280 | + return normalize(basePath + '/' + pathToAdd); |
257 | 281 | } |
258 | | - |
259 | | - return new StringBuffer(lookup). |
260 | | - append(File.separator).append(pth).toString(); |
261 | 282 | } |
262 | 283 |
|
263 | 284 | //----------------------------------------------------------------------- |
@@ -338,8 +359,11 @@ public static int getPrefixLength(String filename) { |
338 | 359 | return 0; |
339 | 360 | } |
340 | 361 | char ch0 = filename.charAt(0); |
| 362 | + if (ch0 == ':') { |
| 363 | + return -1; |
| 364 | + } |
341 | 365 | if (len == 1) { |
342 | | - if (ch0 == '~' || ch0 == ':') { |
| 366 | + if (ch0 == '~') { |
343 | 367 | return -1; |
344 | 368 | } |
345 | 369 | return (isSeparator(ch0) ? 1 : 0); |
|
0 commit comments