@@ -201,7 +201,54 @@ private static boolean isSeparator(char ch) {
201201 * @return the normalized filename, or null if invalid
202202 */
203203 public static String normalize (String filename ) {
204- return doNormalize (filename , true );
204+ return doNormalize (filename , SYSTEM_SEPARATOR , true );
205+ }
206+ /**
207+ * Normalizes a path, removing double and single dot path steps.
208+ * <p>
209+ * This method normalizes a path to a standard format.
210+ * The input may contain separators in either Unix or Windows format.
211+ * The output will contain separators in the format specified.
212+ * <p>
213+ * A trailing slash will be retained.
214+ * A double slash will be merged to a single slash (but UNC names are handled).
215+ * A single dot path segment will be removed.
216+ * A double dot will cause that path segment and the one before to be removed.
217+ * If the double dot has no parent path segment to work with, <code>null</code>
218+ * is returned.
219+ * <p>
220+ * The output will be the same on both Unix and Windows except
221+ * for the separator character.
222+ * <pre>
223+ * /foo// --> /foo/
224+ * /foo/./ --> /foo/
225+ * /foo/../bar --> /bar
226+ * /foo/../bar/ --> /bar/
227+ * /foo/../bar/../baz --> /baz
228+ * //foo//./bar --> /foo/bar
229+ * /../ --> null
230+ * ../foo --> null
231+ * foo/bar/.. --> foo/
232+ * foo/../../bar --> null
233+ * foo/../bar --> bar
234+ * //server/foo/../bar --> //server/bar
235+ * //server/../bar --> null
236+ * C:\foo\..\bar --> C:\bar
237+ * C:\..\bar --> null
238+ * ~/foo/../bar/ --> ~/bar/
239+ * ~/../bar --> null
240+ * </pre>
241+ * The output will be the same on both Unix and Windows including
242+ * the separator character.
243+ *
244+ * @param filename the filename to normalize, null returns null
245+ * @param unixSeparator <code>true</code> if a unix separator should
246+ * be used or <code>false</code> if a windows separtor should be used.
247+ * @return the normalized filename, or null if invalid
248+ */
249+ public static String normalize (String filename , boolean unixSeparator ) {
250+ char separator = (unixSeparator ? UNIX_SEPARATOR : WINDOWS_SEPARATOR );
251+ return doNormalize (filename , separator , true );
205252 }
206253
207254 //-----------------------------------------------------------------------
@@ -247,17 +294,65 @@ public static String normalize(String filename) {
247294 * @return the normalized filename, or null if invalid
248295 */
249296 public static String normalizeNoEndSeparator (String filename ) {
250- return doNormalize (filename , false );
297+ return doNormalize (filename , SYSTEM_SEPARATOR , false );
298+ }
299+
300+ /**
301+ * Normalizes a path, removing double and single dot path steps,
302+ * and removing any final directory separator.
303+ * <p>
304+ * This method normalizes a path to a standard format.
305+ * The input may contain separators in either Unix or Windows format.
306+ * The output will contain separators in the format specified.
307+ * <p>
308+ * A trailing slash will be removed.
309+ * A double slash will be merged to a single slash (but UNC names are handled).
310+ * A single dot path segment will be removed.
311+ * A double dot will cause that path segment and the one before to be removed.
312+ * If the double dot has no parent path segment to work with, <code>null</code>
313+ * is returned.
314+ * <p>
315+ * The output will be the same on both Unix and Windows including
316+ * the separator character.
317+ * <pre>
318+ * /foo// --> /foo
319+ * /foo/./ --> /foo
320+ * /foo/../bar --> /bar
321+ * /foo/../bar/ --> /bar
322+ * /foo/../bar/../baz --> /baz
323+ * //foo//./bar --> /foo/bar
324+ * /../ --> null
325+ * ../foo --> null
326+ * foo/bar/.. --> foo
327+ * foo/../../bar --> null
328+ * foo/../bar --> bar
329+ * //server/foo/../bar --> //server/bar
330+ * //server/../bar --> null
331+ * C:\foo\..\bar --> C:\bar
332+ * C:\..\bar --> null
333+ * ~/foo/../bar/ --> ~/bar
334+ * ~/../bar --> null
335+ * </pre>
336+ *
337+ * @param filename the filename to normalize, null returns null
338+ * @param unixSeparator <code>true</code> if a unix separator should
339+ * be used or <code>false</code> if a windows separtor should be used.
340+ * @return the normalized filename, or null if invalid
341+ */
342+ public static String normalizeNoEndSeparator (String filename , boolean unixSeparator ) {
343+ char separator = (unixSeparator ? UNIX_SEPARATOR : WINDOWS_SEPARATOR );
344+ return doNormalize (filename , separator , false );
251345 }
252346
253347 /**
254348 * Internal method to perform the normalization.
255349 *
256350 * @param filename the filename
351+ * @param separator The separator character to use
257352 * @param keepSeparator true to keep the final separator
258353 * @return the normalized filename
259354 */
260- private static String doNormalize (String filename , boolean keepSeparator ) {
355+ private static String doNormalize (String filename , char separator , boolean keepSeparator ) {
261356 if (filename == null ) {
262357 return null ;
263358 }
@@ -274,22 +369,23 @@ private static String doNormalize(String filename, boolean keepSeparator) {
274369 filename .getChars (0 , filename .length (), array , 0 );
275370
276371 // fix separators throughout
372+ char otherSeparator = (separator == SYSTEM_SEPARATOR ? OTHER_SEPARATOR : SYSTEM_SEPARATOR );
277373 for (int i = 0 ; i < array .length ; i ++) {
278- if (array [i ] == OTHER_SEPARATOR ) {
279- array [i ] = SYSTEM_SEPARATOR ;
374+ if (array [i ] == otherSeparator ) {
375+ array [i ] = separator ;
280376 }
281377 }
282378
283379 // add extra separator on the end to simplify code below
284380 boolean lastIsDirectory = true ;
285- if (array [size - 1 ] != SYSTEM_SEPARATOR ) {
286- array [size ++] = SYSTEM_SEPARATOR ;
381+ if (array [size - 1 ] != separator ) {
382+ array [size ++] = separator ;
287383 lastIsDirectory = false ;
288384 }
289385
290386 // adjoining slashes
291387 for (int i = prefix + 1 ; i < size ; i ++) {
292- if (array [i ] == SYSTEM_SEPARATOR && array [i - 1 ] == SYSTEM_SEPARATOR ) {
388+ if (array [i ] == separator && array [i - 1 ] == separator ) {
293389 System .arraycopy (array , i , array , i - 1 , size - i );
294390 size --;
295391 i --;
@@ -298,8 +394,8 @@ private static String doNormalize(String filename, boolean keepSeparator) {
298394
299395 // dot slash
300396 for (int i = prefix + 1 ; i < size ; i ++) {
301- if (array [i ] == SYSTEM_SEPARATOR && array [i - 1 ] == '.' &&
302- (i == prefix + 1 || array [i - 2 ] == SYSTEM_SEPARATOR )) {
397+ if (array [i ] == separator && array [i - 1 ] == '.' &&
398+ (i == prefix + 1 || array [i - 2 ] == separator )) {
303399 if (i == size - 1 ) {
304400 lastIsDirectory = true ;
305401 }
@@ -312,8 +408,8 @@ private static String doNormalize(String filename, boolean keepSeparator) {
312408 // double dot slash
313409 outer :
314410 for (int i = prefix + 2 ; i < size ; i ++) {
315- if (array [i ] == SYSTEM_SEPARATOR && array [i - 1 ] == '.' && array [i - 2 ] == '.' &&
316- (i == prefix + 2 || array [i - 3 ] == SYSTEM_SEPARATOR )) {
411+ if (array [i ] == separator && array [i - 1 ] == '.' && array [i - 2 ] == '.' &&
412+ (i == prefix + 2 || array [i - 3 ] == separator )) {
317413 if (i == prefix + 2 ) {
318414 return null ;
319415 }
@@ -322,7 +418,7 @@ private static String doNormalize(String filename, boolean keepSeparator) {
322418 }
323419 int j ;
324420 for (j = i - 4 ; j >= prefix ; j --) {
325- if (array [j ] == SYSTEM_SEPARATOR ) {
421+ if (array [j ] == separator ) {
326422 // remove b/../ from a/b/../c
327423 System .arraycopy (array , i + 1 , array , j + 1 , size - i );
328424 size -= (i - j );
0 commit comments